knitr::opts_chunk$set(eval = FALSE)
remove(list = ls())
cran_packages   <- c("knitr", "phyloseqGraphTest", "phyloseq", "shiny", "microbiome",
                     "tidyverse", "miniUI", "caret", "pls", "e1071", "ggplot2", 
                     "randomForest","entropart", "vegan", "plyr", "dplyr", "here",
                     "ggrepel", "nlme", "R.utils", "gridExtra","grid", "googledrive", 
                     "googlesheets", "phangorn", "devtools", "rmarkdown", "sys",
                     "reshape2", "devtools", "PMA","structSSI","ade4", "ape",
                     "Biostrings", "igraph", "ggnetwork", "intergraph", "ips",
                     "scales", "kableExtra", "pgirmess", "treemap", "knitr","kableExtra",
                     "rstudioapi" ,"data.table","DT","pander","formatR","grDevices","svgPanZoom",
                     "RCurl","plotly","pairwiseAdonis", "stringr")
github_packages <- c("jfukuyama/phyloseqGraphTest")
bioc_packages   <- c("phyloseq", "genefilter", "impute", "dada2", "DECIPHER")
# Install CRAN packages (if not already installed)
#Some packages would be not availbale for your R version
inst <- cran_packages %in% installed.packages()
if (any(! inst)) {
  install.packages(cran_packages[!inst], repos = "http://cran.rstudio.com/") }
# 
inst <- github_packages %in% installed.packages()
if (any(! inst)) {
  devtools::install_github(github_packages[!inst]) }

# Load libraries
sapply(c(cran_packages, bioc_packages), require, character.only = TRUE)
sessionInfo()
set.seed(1000)

Preamble

This document is interactive. You can sort and scroll through most of the tables and the phylogenetic tree is zoomable. In the upper right hand corner of the front page is a Code button. Use this to show or hide all the code in the document (default is hide) as well as download the .Rmd file which you can use to extract the code. Data products from the final paper are highlighted in Red.

Definitions & Abbreviations

  • Amplicon Sequence Variant (ASV): Exact sequence variant—analogous to an OTU—but with single nucleotide resolution.
  • Core microbiome (Core): A dispersion index is calculated for each ASV as the ratio of the variance to the mean abundance multiplied by the occurrence :

\[ID_x = \frac{Variance_x}{\sum_{Abondance_x}}\]

where \(ID_x\) is the index of dispersion of the \(ASV_x\). Each calculated index was compared to a Poisson distribution (Magurran & Henderson, 2003), and tested whether they were included between the 2.5% and 97,5% confidence interval of the Khi2 distribution (Krebs, 1999).

  • IR & HR: Impacted Reef and Healthy Reef conditions where IRs are reefs which have undergone a macroalgae invasion while HRs are reefs with a pre-bleaching disturbance state.

Study goals

  1. Describe the distribution of the sampled fish and environmental pieces between reef conditions.
  2. Assess the taxonomic composition of intestinal communities from reef fish and from algae (turf and Sargassum).
  3. Analyse the potential effect of the coral-macroalgal shift on their microbial communities.
  4. Identify which determinants are the drivers of the microbial composition of the enteric microbiome of the reef fish.

Workflow overview

Part I: DADA2 process

The obtained reads from the sequencing platform (Genotoul, Toulouse) were demultiplexed and linkers with primers sequences were removed before being processed through DADA2 pipeline (Callahan et al., 2016). Briefly, sequences were trimmed and filtered for quality, dereplicated and inferred in ASVs (Glassman & Martiny, 2018). Forward and reverse ASVs were merged and finally generated a count table where chimera were identified and removed. The taxonomy assignment was performed using the SILVA reference database (release 123) (Quast et al., 2013). A phyloseq object (McMurdie & Holmes, 2013) was generated for further statistical analysis.

Part II: Phyloseq process

To minimize the effect of contamination during the dissection, extraction and amplification steps, the ASVs taxonomically assigned to Eukarya Kingdom (< 0.1%), the organelles reads (Chloroplast and Mitochondria ) and to 40 kit contaminant genus described in Salter et al. (2014) were removed from the database. Because of the high variability of sequencing depth, tables of ASVs were normalized based on the lowest number of sequences for each compartment (gut, macroalgae and turf). Thus, this part create several phyloseq object in order to use for the alpha and beta diversity.

Part III: Fish Community Composition between Reefs

Before analyzing the microbial compositions, we assess the host distribution between reefs. The macroalga shift has already been study to alter fish communities and trophic structure (Burkepile & Hay, (2008) ; Nyström et al., (2008)). We first analyze our sampling results in order to underpinned the previous observations and to understand how microbiome is adapted to the health reef status.

Part IV: Determination and description of the enteric and algal core microbiomes

We first describe the core microbiome as microbiome constituted by theoritical permanent ASVs. I a first step, enteric and macro-algal core bacteriomes were independently identified by examining the species abundance distribution (SAD) patterns of each ASV and by partitioning the SAD into core and satellite ASVs (Magurran & Henderson, 2003). For this purpose, the index of dispersion for each ASV was calculated as the ratio of the variance to the mean abundance (VMR) multiplied by the occurrence. \[ID_x = \frac{Variance_x}{\sum_{Abondance_x}}\]

where \(ID_x\) is the index of dispersion of the \(ASV_x\). This index was used to model whether lineages follow a Poisson distribution (i.e., stochastic distribution), falling between the 2.5 and 97.5% confidence interval of the χ2 distribution (Krebs, 1999). Concerning the alpha diversity, tables were normalized with the abundance of the minimal sampling size. Richness observed and Shannon index were calculated and compared between both compartment. Then, the beta diversity was calculated with the normalized tables for both cores. A blast on the different ASVs was also made and ploted through Itol in order to determine the origin of the ASVs in the enteric and algal cores. Also, to detect the taxa descriptor of each compartment, we proceeded to a Linear Discriminant analyses on LefSe to detect which ASVs are biomarkers of each compartments (Segata et al., 2011).

Part V: Influence of the coral-macrolagal shift on microbial compositions

In this part, we treated the main issue comparing the environmental samples and enteric core microbiomes from HRs and IRs with alpha diversity and beta diversity with PERMANOVA. Concerning the enteric microbiome, our sampling size permited to test four species (Aprion virescens, Scarus ghobban, Lethrinus mahsena and Lethrinus enigmaticus), two genus (Lethrinus sp., Scarus sp.) and one family (Lutjanidae).

Part VI: Other drivers of enteric microbial communities

Finally, in order to determine which determinants are the drivers of the microbial composition of the enteric microbiome of the reef fish, we tested the effect of the phylogeny and the diet by comparing the herbivore and the invertivores. As for the Part IV, we generated a LDA in order to detect the microbial taxa biomarkers for each diet.

Ps: All tables and figures presented below were possibly modify before to be insert in the publication. We also include many additional data productes that were not part of the original publication.


Part I: DADA2 process

back to top

Preparation of your sequence

First, you need to load the original R1 R2 reads in the /dir_fastq_source folder. Then, download the SILVA database references into the /dir_ref_db folder. Concerning the primers 515F-Y & 926R used for this publication, their sequences are written right here. You can also write a .txt files for each primer you used and load it in the /dir_primers folder to call them when you need it.

primer_515FY <- "GTGYCAGCMGCCGCGGTAA"
primer_926R <- "CCGYCAATTYMTTTRAGTTT"

We need to read the folders which contain our sequences,primers sequences, environmental dataset and references.

library(stringr)
nms_seq_runs  <- list.files(dir_fastq_source)
paths_seq_runs <- list.files(dir_fastq_source, full.names = TRUE) %>% setNames(nms_seq_runs)

nms_refdb   <- list.files(dir_refdb)
paths_refdb <- list.files(dir_refdb, full.names = TRUE) %>% setNames(nms_refdb)

nms_primers   <- list.files(dir_primers)
paths_primers <- list.files(dir_primers, full.names = TRUE) %>% setNames(nms_primers)

You have R1 and R2 reads with the corresponding sequencing names which can be very ugly. First, get the list of your samples and exctract the sample names:

fns <- sort(list.files(dir_sample_selection, full.names = TRUE))
fns <- fns[str_detect(basename(fns), ".fastq")]
fns_R1 <- fns[str_detect(basename(fns), "R1")]
fns_R2 <- fns[str_detect(basename(fns), "R2")]
if(length(fns_R1) != length(fns_R2)) stop("Forward and reverse files do not match.")

sample_names <- sapply(strsplit(basename(fns_R1), "_"), `[`, 1)
sample_names

Once sample names cut, you can remove the primer sequence from your data by “counting” the number of nucleotides of each primer. Because nucleotides maybe me flowing, it not advised to remove the sequence of the primer by its nucleotide composition.

library(readr)
primer_set_fwd <- read_lines(paste0(dir_primers, "primer_", "515F-Y" , ".txt"))
primer_set_rev <- read_lines(paste0(dir_primers, "primer_", "926R", ".txt"))
primer_length_fwd <- str_length(primer_set_fwd[2])
primer_length_rev <- str_length(primer_set_rev[1])

# You can also use the sequence of the {r primers description}

Quality profiles and filter/trim the sequences

Now you can plot the quality profiles of your reads (which is usely better on the R1) in order to truncate the sequences before quality drastically decrease. Then, you can filter your sequences and trim the primer length.

dir_quality_plots <- paste0(dir_seq_processing, "/quality_pdf/plots/")
dir_create(dir_quality_plots , recursive = T)
qual_R1 <- plotQualityProfile(fns_R1[1])
qual_R2 <- plotQualityProfile(fns_R2[1])

ggsave(qual_R1, file = paste0(dir_quality_plots , "quality_profile_R1.png"))
ggsave(qual_R2, file = paste0(dir_quality_plots, "quality_profile_R2.png"))

filt_R1 <- str_c(dir_filtered, sample_names, "_R1_filt.fastq")
filt_R2 <- str_c(dir_filtered, sample_names, "_R2_filt.fastq")
names(filt_R1) <- sample_names
names(filt_R2) <- sample_names
set.seed(1000)

out <- filterAndTrim(fns_R1, filt_R1, fns_R2, filt_R2, truncLen=c(240,240),
                     maxN=0, maxEE=c(2,2), truncQ=2, trimLeft=c(primer_length_fwd,primer_length_rev) , rm.phix=TRUE,
                     compress=TRUE, multithread=TRUE)
head(out)

sample_names <- sapply(strsplit(basename(filt_R1), "_"), `[`, 1) # Assumes filename = samplename_XXX.fastq.gz
sample_namesR <- sapply(strsplit(basename(filt_R2), "_"), `[`, 1) # Assumes filename = samplename_XXX.fastq.gz
if(!identical(sample_names, sample_namesR)) stop("Forward and reverse files do not match.")
names(filt_R1) <- sample_names
names(filt_R2) <- sample_names
set.seed(1000)

Finally, you can learn the error rates for both reads and save them.

errF <- learnErrors(filt_R1,nbases=1e8, multithread=TRUE)
errR <- learnErrors(filt_R2, nbases=1e8, multithread=TRUE)
plotErrors_F <- plotErrors(errF, nominalQ=TRUE)
plotErrors_R <- plotErrors(errR, nominalQ=TRUE)
ggsave(plotErrors_F, file = paste0(dir_quality_plots , "plotErrors_F.png"))
ggsave(plotErrors_R, file = paste0(dir_quality_plots, "plotErrors_R.png"))

Ps: If you have big data, please proceed directly at the Part Ib: DADA2 process for BIG DATA.

Dereplication and merging sequences

Now, we dereplicate the filtered reads in order to infer them in dada file to merge.

#Dereplication step
derepFs <- derepFastq(filt_R1, verbose=TRUE)
derepRs <- derepFastq(filt_R2, verbose=TRUE)
names(derepFs) <- sample_names
names(derepRs) <- sample_names
# Inference step
dadaFs <- dada(derepFs, err=errF, multithread=TRUE, pool = T)
dadaRs <- dada(derepRs, err=errR, multithread=TRUE, pool = T)
dadaFs[[1]]
dadaRs[[1]]
# Merging step
mergers <- mergePairs(dadaFs, derepFs, dadaRs, derepRs, verbose=TRUE)
head(mergers[[1]])

Now, we can construct our sequence table “seqtab” and remove chimeras. It is recommandable to track the reads through the pipeline process

seqtab <- makeSequenceTable(mergers)
row.names(seqtab) = sample_names
dim(seqtab)
table(nchar(getSequences(seqtab)))

seqtab.nochim <- removeBimeraDenovo(seqtab, method="consensus", multithread=TRUE, verbose=TRUE)
dim(seqtab.nochim)
sum(seqtab.nochim)/sum(seqtab)
saveRDS(seqtab.nochim, paste0(dir_seq_processing,"seqtab.nochim.rds"))

# ____ Track reads through the pipeline ----
getN <- function(x) sum(getUniques(x))
track <- cbind(out, sapply(dadaFs, getN), sapply(mergers, getN), rowSums(seqtab), rowSums(seqtab.nochim))
colnames(track) <- c("input", "filtered", "denoised", "merged", "tabled", "nonchim")
rownames(track) <- sample_names
head(track)
save(track, file = "track_515F-Y_926R.RData")

Part Ib: DADA2 process for BIG DATA

back to top

These chunks are highly recommendable if you have a huge mount of sequences !

mergers <- vector("list", length(sample_names))
names(mergers) <- sample_names
for(sam in sample_names) {
  cat("Processing:", sam, "\n")
  derepFs <- derepFastq(filt_R1[[sam]])
  ddF <- dada(derepFs, err=errF, multithread=TRUE)
  derepRs <- derepFastq(filt_R2[[sam]])
  ddR <- dada(derepRs, err=errR, multithread=TRUE)
  merger <- mergePairs(ddF, derepFs, ddR, derepRs)
  mergers[[sam]] <- merger
}
rm(derepFs); rm(derepRs)

Now the construction of the sequence table

seqtab <- makeSequenceTable(mergers)
row.names(seqtab) = sample_names
dim(seqtab)
table(nchar(getSequences(seqtab)))

saveRDS(seqtab, paste0(dir_seq_processing,"seqtab.rds"))

# If processing a single sample, remove the sapply calls: e.g. replace sapply(dadaFs, getN) with getN(dadaFs)
colnames(track) <- c("input", "filtered", "tabled")
rownames(track) <- sample_names
head(track)
save(track, file = "table_track_A515F-Y_926R.RData")

And remove chimeras as the other part :

seqtab.nochim <- removeBimeraDenovo(seqtab, method="consensus", multithread=TRUE, verbose=TRUE)
dim(seqtab.nochim)
sum(seqtab.nochim)/sum(seqtab)
saveRDS(seqtab.nochim, paste0(dir_seq_processing,"seqtab.nochim.rds"))

Taxonomy assignment

You have already load the SILVA ref files, then you have to assign from them the sequence tables

load(dir_seq_processing , "seqtab.nochim.rds")

path_reference_db <- paste0(dir_refdb, "silva_nr_v132_train_set.fa.gz")
path_species_db   <- paste0(dir_refdb, "silva_species_assignment_v132.fa.gz")
taxaRC <- assignTaxonomy(seqtab.nochim, path_reference_db, tryRC=TRUE)
taxaSp <- addSpecies(taxaRC, path_species_db) # This step can be very long

taxa.print <- taxaSp # Removing sequence rownames for display only
rownames(taxa.print) <- NULL
head(taxa.print)

saveRDS(seqtab.nochim,taxaRC, taxaSp, file= paste0(dir_seq_processing,"dada2_files.rds"))

Part II: Phyloseq process

back to top

Now you can create your phyloseq object with your filtered and assigned sequences. Before running the phyloseq process, you need to clean your worspace in order to free the r stack memory

And set_wd again

Phyloseq object creation

We can create our phyloseq object from the seqtab.nochim file created previously.

load(paste0(dir_taxa_assign,"dada2_files.rds"))
load(paste0(dir_taxa_assign,"seqtab.nochim_515F-Y.926R.RData"))

ps <- phyloseq(otu_table(seqtab.nochim, taxa_are_rows=FALSE),tax_table(taxaRC)) 
# You can use tax_table(taxaSp) if you need the assignment until species level

Now, we will modify our table with ASVs names

dna <- Biostrings::DNAStringSet(taxa_names(ps))
names(dna) <- taxa_names(ps)
ps <- merge_phyloseq(ps, dna)
taxa_names(ps) <- paste0("ASV", seq(ntaxa(ps)))
ps
save(ps, taxaRC,seqtab.nochim, seqtab, file=paste0(dir_taxa_assign ,"ps_515F-Y.926R.RData"))
# First results 
ntaxa(ps)
nsamples(ps)
sample_names(ps)[1:5]
rank_names(ps)
otu_table(ps)[1:5, 1:5]
tax_table(ps)[1:5, 1:6]

Presentation of the envdata

The envdata is constituted of the sampling data for the gut, algae and turf samples. * Tax_information : The informations concerning the species are written in different ways with tax1 as the Species genus, tax2 as the Species_genus nomenclature, tax3 as the SPG_x which is the corresponding two first letters of the species and the first of the genus followed by the x of the sampled individuals in this species. The type, lineage, Order, Family ,Genus and Species are mentioned.

  • Diet_information: The Diet is mentionned at high scale with the diet3 and at granulous scales following the ecological traits in Mouillot et al., (2014). The diet4 mentionned the difference in the herbivory for the Scaridae, Acanthuridae and Siganidae species. Also, the trophic position is mentionned with the FishBase reference.

  • Individual_information: For each individual, the weight mass, total length, gut mass and sex were obtained.

  • Site_information: Site with the GPS coordonates were taken and the geomorphology were attributed to the condition of the reef.

envdata <- read.csv2(paste0(dir_refdb, "env.csv"))
colnames(envdata)[1] = "ID"
datatable(envdata[-c(3,6,10, 12)], rownames = FALSE, width = "100%",
          colnames = c("ID", "Species","Species number" ,"Compartment","Order","Family","Genus","Diet abreviation","Diet High scale","Diet Low scale","Trophic position", "Mass (g)","Total Length (cm)","Gut mass (g)","Sex","Site","Reef condition","GPS latitude","GPS longitude", "Island", "Substrat"), 
          caption = htmltools::tags$caption(style = "caption-side: 
                                            bottom; text-align: left;", 
                                            "Table: ", 
                                            htmltools::em("Sample presentation.")), 
          extensions = "Buttons", 
          options = list(columnDefs = 
                           list(list(className = "dt-left", targets = 0)), 
                         dom = "Blfrtip", pageLength = 5, 
                         lengthMenu = c(5, 10, 25, 50), 
                         buttons = c("csv", "copy"), 
                         scrollX = TRUE, scrollCollapse = TRUE))

It’s just an parenthesis for ordering envdata depending of your phyloseq objects. It is a step a bit borring but necessary if your env file is not synchro with your phyloseq object, meaning that the samples names in your env file are not the same that your sample names in the phyloseq object. First, we will order the names

load(paste0(dir_taxa_assign, "dada2_files.RData"))
nochim_names <- rownames(seqtab.nochim)
env_names <- as.character(envdata$ID)

Now, the aim is to have exactly the same names in the phyloseq object and in the env table.

lecture <- cbind(sort(nochim_names),sort(env_names))
identical(lecture[,1], lecture[,2]) 

If it’s True, you’re names are the same, directly pass to the merging step; If False, you have to replace the correct names. Also, you have to check your env file with the names of your fish species, genus or family which could be incorrect.

levels(factor(envdata$family))
levels(factor(envdata$species))

Merging data

Now that the seqtab and the envdata are corresponding, we will merge them into phyloseq object.

load(paste0(dir_taxa_assign,"ps_515F-Y.926R.RData"))
envdata <- read.csv2(paste0(dir_refdb, "env.csv"))
colnames(envdata)[1] = "ID"
DAT <- sample_data(envdata)
DAT
sort(sample_names(DAT)) == sort(sample_names(ps)) # must be true to be merged

ps1<- merge_phyloseq(ps, DAT)
ps1
save(ps1, envdata,file=paste0(dir_taxa_assign ,"ps1_515F-Y.926R.RData"))

Plot the sample minimum ASV

min(rowSums(ps1@otu_table@.Data))
readsumsdf = data.frame(nreads = sort(taxa_sums(ps1),TRUE), sorted = 1:ntaxa(ps1), type = "ASVs")
readsumsdf = rbind(readsumsdf, data.frame(nreads = sort(sample_sums(ps1), TRUE), sorted = 1:nsamples(ps1), type = "Samples"))

title = "Total number of reads"
pdf(file = paste0(dir_quality_plots, "total_number_of_reads.pdf"), he = 7, wi = 7)
p = ggplot(readsumsdf, aes(x = sorted, y = nreads)) + geom_bar(stat = "identity")
p + ggtitle(title) + scale_y_log10() + facet_wrap(~type, 1, scales = "free")
dev.off()

Phyloseq creation

We will filter our ps1 to only keep the Prokaryotes

load(paste0(dir_taxa_assign, "ps1_515F-Y.926R.RData"))
ps_sey_proka <- subset_taxa(ps_sey , Kingdom %in% c("Archaea", "Bacteria"))
save(ps_sey_proka, file = paste0(dir_taxa_assign, "ps_sey_proka.RData"))

Then, we will obtain the phylogenetic distances between ASVs The tree was obtained after aligning the sequences on mothur and was names “Sey.tree” and was load in the *_taxa_assign* folder. The assignment was made against the ARB database available on SILVA database reference (v132) and proceeded on Mothur platform.

sey_tree <- read.tree(paste(dir_taxa_assign, "Sey.tree"))
sey_tree2 <- root(sey_tree, "ASV40619", resolve.root = T)
sey_tree2 <- drop.tip(sey_tree2,"ASV40619" ) # To delete the outgroup ASV

library(picante)
cal1<-makeChronosCalib(sey_tree2, node = "root", age.min = 1, age.max = 1, interactive = FALSE, soft.bounds = FALSE) #calibration for ultrametric branchs.
sey_chronogramme<-chronos(sey_tree2, lambda=0, model = "discrete", cal=cal1, quiet = FALSE, control=chronos.control(nb.rate.cat=1))
save(sey_chronogramme ,file = paste0(dir_taxa_assign ,"sey_chronogramme.Rdata"))

ps_sey_tree <- merge_phyloseq(ps_sey_proka, sey_tree2)
save(ps_sey_tree, file = paste0(dir_taxa_assign, "ps_sey_tree.RData"))

Now that the phyloseq is only made by Prokaryotes which phylogenetic distances are associated, we will finally filter all organels (Chloroplast and Mitochondria) and potential contaminants of the exctraction kits and steps of amplification as mentionned in Salter et al., 2014.

Clean the phyloseq object

cont_list <- read.csv("/Users/marie-charlottecheutin/Drive/Thesis/Seychelles/WP5.3_data/data_sources/reference_databases/list_potential_contaminants.csv")
contaminant <- cont_list$Genus
sey_final <- subset_taxa(ps_sey_tree, Order != "Chloroplast")
sey_final <- subset_taxa(sey_final , Family != "Mitochondria")
sey_contaminant <- subset_taxa(sey_final , Genus %in% contaminant)
save(sey_contaminant , file = paste0(dir_taxa_assign, "sey_contaminant.Rdata"))
sey_final <- subset_taxa(sey_final , !Genus %in% contaminant)
save(sey_final, file = paste0(dir_taxa_assign,"sey_final.RData"))
seyrff_final  <- prune_samples(sample_sums(sey_final) >= min(sample_sums(sey_final)) , sey_final)
seyrff_final <- rarefy_even_depth(seyrff_final, sample.size = min(sample_sums(sey_final)))
save(seyrff_final, file = paste0(dir_taxa_assign, "seyrff_final.RData"))

Now we have the final phyloseq for all the samples, we can subset the phyloseq object for the gut, the algae and the turf and rarefy them. To be sure that the minimal abundance of the data set is enough to capture all the diversity, we use the function ggrare()

ggrare <- function(physeq_object, step = 10, label = NULL, color = NULL, plot = TRUE, parallel = FALSE, se = TRUE) {

  x <- methods::as(phyloseq::otu_table(physeq_object), "matrix")
  if (phyloseq::taxa_are_rows(physeq_object)) { x <- t(x) }
## This script is adapted from vegan `rarecurve` function
  tot <- rowSums(x)
  S <- rowSums(x > 0)
  nr <- nrow(x)

  rarefun <- function(i) {
    cat(paste("rarefying sample", rownames(x)[i]), sep = "\n")
    n <- seq(1, tot[i], by = step)
    if (n[length(n)] != tot[i]) {
      n <- c(n, tot[i])
    }
    y <- vegan::rarefy(x[i, ,drop = FALSE], n, se = se)
    if (nrow(y) != 1) {
      rownames(y) <- c(".S", ".se")
      return(data.frame(t(y), Size = n, Sample = rownames(x)[i]))
    } else {
      return(data.frame(.S = y[1, ], Size = n, Sample = rownames(x)[i]))
    }
  }
  if (parallel) {
    out <- parallel::mclapply(seq_len(nr), rarefun, mc.preschedule = FALSE)
  } else {
    out <- lapply(seq_len(nr), rarefun)
  }
  df <- do.call(rbind, out)

  # Get sample data
  if (!is.null(phyloseq::sample_data(physeq_object, FALSE))) {
    sdf <- methods::as(phyloseq::sample_data(physeq_object), "data.frame")
    sdf$Sample <- rownames(sdf)
    data <- merge(df, sdf, by = "Sample")
    labels <- data.frame(x = tot, y = S, Sample = rownames(x))
    labels <- merge(labels, sdf, by = "Sample")
  }

  # Add, any custom-supplied plot-mapped variables
  if ( length(color) > 1 ) {
    data$color <- color
    names(data)[names(data) == "color"] <- deparse(substitute(color))
    color <- deparse(substitute(color))
  }

  if ( length(label) > 1 ) {
    labels$label <- label
    names(labels)[names(labels) == "label"] <- deparse(substitute(label))
    label <- deparse(substitute(label))
  }

  p <- ggplot2::ggplot(data = data,
                       ggplot2::aes_string(x = "Size",
                                           y = ".S",
                                           group = "Sample",
                                           color = color))

  p <- p + ggplot2::labs(x = "Sequence Sample Size", y = "Species Richness")

  if (!is.null(label)) {
    p <- p + ggplot2::geom_text(data = labels,
                                ggplot2::aes_string(x = "x",
                                                    y = "y",
                                                    label = label,
                                                    color = color),
                       size = 4, hjust = 0)
  }

  p <- p + ggplot2::geom_line()
  if (se) { ## add standard error if available
    p <- p +
      ggplot2::geom_ribbon(ggplot2::aes_string(ymin = ".S - .se",
                                               ymax = ".S + .se",
                                               color = NULL,
                                               fill = color),
                           alpha = 0.2)
  }
  if (plot) {
    plot(p)
  }
  invisible(p)
}

And now use it and create the phyloseq objects

Subset the phyloseq objects

load(paste0(dir_taxa_assign, "sey_final.RData"))
# Fish ps 
sey_gut <- subset_samples(sey_final, type == "gut")
sey_gut <- prune_taxa(names(which(colSums(sey_gut@otu_table)>0)), sey_gut)
save(sey_gut, file = paste0(dir_taxa_assign, "sey_gut.RData"))
sort(sample_sums(sey_gut))
set.seed(10000)
p_gut <- ggrare(sey_gut, step = 500, color = "geomorpho", label = "tax1", se = FALSE)

seyrff_gut <- prune_samples(sample_sums(sey_gut) >= min(sample_sums(sey_gut)) , sey_gut)
seyrff_gut <- rarefy_even_depth(seyrff_gut, sample.size = min(sample_sums(sey_gut)))
save(seyrff_gut, file = paste0(dir_taxa_assign, "seyrff_gut.RData"))
# Algae ps 
sey_algae <- subset_samples(sey_final, tax1 %in% c("macroalgae", "turf"))
sey_algae <- prune_taxa(names(which(colSums(sey_algae@otu_table)>0)), sey_algae)
save(sey_algae, file = paste0(dir_taxa_assign, "sey_algae.RData"))
set.seed(10000)
p_algae <- ggrare(sey_algae, step = 500, color = "geomorpho", label = "tax1", se = FALSE)

seyrff_algae <- prune_samples(sample_sums(sey_algae) >= min(sample_sums(sey_algae)) , sey_algae)
seyrff_algae <- rarefy_even_depth(seyrff_algae, sample.size = min(sample_sums(sey_algae)))
save(seyrff_algae, file = paste0(dir_taxa_assign, "seyrff_algae.RData"))

Part III: Fish Community Composition between Reefs

back to top

Here again, we will remove all the object to clean the memory

And set_wd again

In this is part, we will focus on our sampling dataset and analyze the distribution of the hosts between the IRs and HRs.

envdata <- read.csv2(paste0(dir_refdb, "env.csv"))
colnames(envdata)[1] = "ID"
load(paste0(dir_taxa_assign, "sey_gut.RData"))
load(paste0(dir_taxa_assign, "sey_final.RData"))

We will first write the table of the species and their corresponding diet.

diet_sp <- as.data.frame(table(envdata$diet4, envdata$tax1))[which(as.data.frame(table(envdata$diet4, envdata$tax1))[,3]> 0),][,c(1,2)]
sp_reef <- table(envdata$tax1, envdata$geomorpho)
sp_reef <- cbind(as.data.frame(sp_reef[,1]), as.data.frame(sp_reef[,2]))
table_diet_sp <- cbind(diet_sp[,2],diet_sp[,1],sp_reef[,c(1,2)])

table_to_print <- rbind(table_diet_sp[-c(26,37),], table_diet_sp[c(26,37),])
datatable(table_to_print, rownames = F, width = "100%",
          colnames = c("Species", "Diet", "HR","IR"),
          caption = htmltools::tags$caption(style = "caption-side: 
                                            bottom; text-align: left;", 
                                            "Table: ", 
                                            htmltools::em("Sampling table of the species and diet between reefs.")), 
          extensions = "Buttons", 
          options = list(columnDefs = 
                           list(list(className = "dt-left", targets = 0)), 
                         dom = "Blfrtip", pageLength = 5, 
                         lengthMenu = c(5, 10, 25, 50), 
                         buttons = c("csv", "copy"), 
                         scrollX = TRUE, scrollCollapse = TRUE))
PCoA on fish community

The distribution of the sampling set is a first result showing the influence of the shift on the fish communities. How are they distributed?

samp_data <- envdata[envdata$type=="gut",]
fam_tab <- table(samp_data$site,samp_data$family)

# Transform to log
fam.log <- log1p(fam_tab)  # Equivalent: log(fam_tab + 1)
# Principal coordinate analysis and simple ordination plot
fam.D <- vegdist(fam.log, "bray")
res <- pcoa(fam.D)
#res$values
biplot(res, fam.log)

#round(res$values$Relative_eig[1]*100, 1) # 57.8 %
#round(res$values$Relative_eig[2]*100, 1) # 26 %

site1 <- c("C1","C2","C3","C4", "M1","M2","M3")
site2 <- c(rep("coral", 4), rep("macroalgal",3))
site_data <- cbind(site1,site2)
colnames(site_data) <- c("site", "geomorpho")
site_data <- as.data.frame(site_data)

adonis(fam.D ~ geomorpho, data = site_data)
## 
## Call:
## adonis(formula = fam.D ~ geomorpho, data = site_data) 
## 
## Permutation: free
## Number of permutations: 5039
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## geomorpho  1   0.39044 0.39044  2.9776 0.37324  0.031 *
## Residuals  5   0.65564 0.13113         0.62676         
## Total      6   1.04608                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
beta_reef <- betadisper(fam.D, site_data$geomorpho)
permutest(beta_reef)
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 5039
## 
## Response: Distances
##           Df   Sum Sq   Mean Sq      F N.Perm Pr(>F)
## Groups     1 0.004688 0.0046883 0.4681    999  0.512
## Residuals  5 0.050075 0.0100150

Now, we will do the same on trophic srtucture with the diet

samp_data <- envdata[envdata$type=="gut",]
diet_tab <- table(samp_data$site,samp_data$diet4)
# Transform to log
diet.log <- log1p(diet_tab)  # Equivalent: log(diet_tab + 1)
# Principal coordinate analysis and simple ordination plot
diet.D <- vegdist(diet.log, "bray")
res <- pcoa(diet.D)
#res$values
par(mfrow=c(1,2))
biplot(res, diet.log)
#round(res$values$Relative_eig[1]*100, 1) # 74.1 %
#round(res$values$Relative_eig[2]*100, 1) # 17.8 %

site1 <- c("C1","C2","C3","C4", "M1","M2","M3")
site2 <- c(rep("coral", 4), rep("macroalgal",3))
site_data <- cbind(site1,site2)
colnames(site_data) <- c("site", "geomorpho")
site_data <- as.data.frame(site_data)

adonis(diet.D ~ geomorpho, data = site_data)
## 
## Call:
## adonis(formula = diet.D ~ geomorpho, data = site_data) 
## 
## Permutation: free
## Number of permutations: 5039
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## geomorpho  1   0.32919 0.32919  5.2907 0.51412  0.034 *
## Residuals  5   0.31110 0.06222         0.48588         
## Total      6   0.64029                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
beta_reef <- betadisper(diet.D, site_data$geomorpho)
permutest(beta_reef)
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 5039
## 
## Response: Distances
##           Df   Sum Sq   Mean Sq      F N.Perm Pr(>F)
## Groups     1 0.007975 0.0079747 0.5265    999   0.44
## Residuals  5 0.075726 0.0151452

Because we will focus our sutdy on herbivores and invertivores, we need to know if families are equally distributed.

samp_data_inv <- samp_data[samp_data$diet4 == "Mobile invertebrate",]
fam_tab <- table(samp_data_inv$site,samp_data_inv$family)
# Transform to log
fam.log <- log1p(fam_tab)  # Equivalent: log(fam_tab + 1)
# Principal coordinate analysis and simple ordination plot
fam.D <- vegdist(fam.log, "bray")
res <- pcoa(fam.D)
#res$values
biplot(res, fam.log)

#round(res$values$Relative_eig[1]*100, 1) # 57.8 %
#round(res$values$Relative_eig[2]*100, 1) # 26 %

site1 <- c("C1","C2","C3","C4", "M1","M2","M3")
site2 <- c(rep("coral", 4), rep("macroalgal",3))
site_data <- cbind(site1,site2)
colnames(site_data) <- c("site", "geomorpho")
site_data <- as.data.frame(site_data)

adonis(fam.D ~ geomorpho, data = site_data)
## 
## Call:
## adonis(formula = fam.D ~ geomorpho, data = site_data) 
## 
## Permutation: free
## Number of permutations: 5039
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs  MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1   0.02326 0.023259 0.11416 0.02232  0.917
## Residuals  5   1.01868 0.203736         0.97768       
## Total      6   1.04194                  1.00000
beta_reef <- betadisper(fam.D, site_data$geomorpho)
permutest(beta_reef)
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 5039
## 
## Response: Distances
##           Df   Sum Sq  Mean Sq      F N.Perm Pr(>F)
## Groups     1 0.027353 0.027353 0.6528    999  0.593
## Residuals  5 0.209495 0.041899

Part IV: Determination and description of the enteric and algal core microbiomes

back to top

Colors

Microbial community of fish is very high and it is very difficult to discern less than 10 taxa. That’s why, we kept the same color for the same taxa, in order to be able to compare the graphs between compartemtn, diet or fish families. Of course, if your are only interested in some taxa, better choose few colors. For the bigger table (i.e tax table at Order level), distinctColorPalette() could be very useful but be awared that colors are not repeated. Here is the code :

phylum_colors <- c('Acidobacteria'='lavenderblush4',
                   'Actinobacteria'='darkblue',
                   'Armatimonadetes'='cadetblue3',
                   'Bacteroidetes'='cornflowerblue',
                   'Calditrichaeota'='azure3',
                   'Chloroflexi'='#DCE1D2',
                   'Cyanobacteria'='#DE6554',
                   'Dadabacteria'='brown2',
                   'Deferribacteres'='darkslategray1',
                   'Deinococcus-Thermus'='salmon4',
                   'Dependentiae'='sandybrown',
                   'Epsilonbacteraeota'='darkslateblue',
                   'Elusimicrobia'='plum1',
                   'Euryarchaeota'='hotpink4',
                   'Firmicutes'='brown4',
                   'Fusobacteria'='orange',
                   'Gemmatimonadetes'='darkolivegreen',
                   'Kiritimatiellaeota'='darkkhaki',
                   'Marinimicrobia_(SAR406_clade)'='darkgoldenrod4',
                   'Latescibacteria'='darkseagreen2',
                   'Lentisphaerae'='darkseagreen4',
                   'Patescibacteria'='darkturquoise',
                   'Planctomycetes'='darkslategray',
                   'Proteobacteria'='aquamarine4',
                   'Spirochaetes'='darkolivegreen3',
                   'Tenericutes'='#CA8EA7',
                   'Thaumarchaeota'='gold3',
                   'Verrucomicrobia'='darkgreen',
                   'WPS-2'='thistle2',
                   'Other'= 'black',
                   'Z-Other' = 'black')

class_colors <- c("Acidimicrobiia"="darksalmon",
                  "Acidobacteriia"="lavenderblush4",
                  "Actinobacteria"="darkblue",
                  "Alphaproteobacteria"="lightseagreen",
                  "Babeliae"="peachpuff",
                  "Anaerolineae"="tomato2",
                  "Bacilli"="brown4",
                  "Bacteroidia"="cornflowerblue",
                  "Brachyspirae"="darkolivegreen2",
                  "Campylobacteria"="royalblue",
                  "Clostridia"="orange3",
                  "Coriobacteriia"="deepskyblue4",
                  "Deferribacteres"="darkslategray1",
                  "Deinococci"="skyblue3",
                  "Deltaproteobacteria"="skyblue4",
                  "Erysipelotrichia"="yellow",
                  "Fusobacteriia"="orange",
                  "Fimbriimonadia" = "darkseagreen",
                  "Gammaproteobacteria"="aquamarine4",
                  "Kiritimatiellae"="darkgray",
                  "Lentisphaeria"="darkseagreen4",
                  "Microgenomatia"="seashell3",
                  "Mollicutes"="#CA8EA7",
                  "Negativicutes"="palevioletred4",
                  "Nitrososphaeria"="sandybrown",
                  "Oxyphotobacteria"="#DE6554",
                  "Phycisphaerae"="rosybrown4",
                  "Planctomycetacia"="darkslategray",
                  "Rhodothermia"="cornsilk3",
                  "Spirochaetia"="darkolivegreen3",
                  "Thermoanaerobaculia"="purple",
                  "Thermoleophilia"="deeppink4",
                  "Verrucomicrobiae"="darkgreen")

#library(randomcoloR)
#n <- length(levels(core_physeq_order$Order))
#order_colors <- distinctColorPalette(n)

Let’s analyze our data previously proceeded. In order to descrimine which ASVs are rare (transients) and which would be considered as permanent (core), we use a dispersion index for each ASV and compare it at the Poisson distribution to determine which ASVs are signifcantly randomly distributed (transiant) and which are not (core) following the method of Fillol et al. (2016).


Part IVa: Enteric core microbiome

back to top

We create a new folder for the enteric microbiome of reef fish and determine the core.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Core/")
dir.create(dir_data_cleaning, recursive = T)
load(paste0(dir_taxa_assign, "sey_gut.RData"))
load(paste0(dir_taxa_assign, "seyrff_gut.RData"))

Core determination

library(labdsv)
otu_table <- seyrff_gut@otu_table@.Data
abuoccplot_otu <- abuocc(otu_table)

## Press return for next plot

## Press return for next plot

## Do you want to identify individual species? Y/N : 
## Press return for next plot

## Do you want to identify individual plots? Y/N :
#sub_objects of abuocc objects
str(abuoccplot_otu)
## List of 3
##  $ spc.plt: Named int [1:99] 15 9 12 38 29 13 28 9 13 6 ...
##   ..- attr(*, "names")= chr [1:99] "AVR-001" "AVR-002" "AVR-005" "AVR-007" ...
##  $ plt.spc: Named int [1:2768] 1 1 1 1 1 2 1 1 1 1 ...
##   ..- attr(*, "names")= chr [1:2768] "ASV30583" "ASV16988" "ASV12732" "ASV538" ...
##  $ mean   : Named num [1:2768] 1 11 8 9 9 7 6 3 14 5 ...
##   ..- attr(*, "names")= chr [1:2768] "ASV30583" "ASV16988" "ASV12732" "ASV538" ...
##  - attr(*, "call")= language abuocc(comm = otu_table)
##  - attr(*, "comm")= chr [1:14961] "structure(list(ASV30583 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, " ...
##  - attr(*, "timestamp")= chr "Fri Jul 10 16:56:02 2020"
##  - attr(*, "class")= chr "abuocc"
# transform spc.plt vector into table in order to calculate specific richness
richness_otu <- data.frame(abuoccplot_otu$spc.plt)
# occurence of each OTU
otu_occurence <- data.frame(abuoccplot_otu$plt.spc)
mean.abun_otu <- colSums(otu_table)/otu_occurence
square_otu <- otu_table^2
ss_otu <- data.frame(colSums(square_otu))
# Variance calculation
variance_otu=ss_otu/otu_occurence-mean.abun_otu^2
disp_otu <- (variance_otu/mean.abun_otu)*otu_occurence
# IC calculation for Poisson distribution using Chi square distribution (value and formula within Zar p574)
library(epitools)
poisic_otu = pois.exact(otu_occurence, conf.level = 0.95)
gut_dstat_otu <- cbind(mean.abun_otu, disp_otu, otu_occurence, poisic_otu)
names(gut_dstat_otu) <- c("average","disp", "occurence", "x", "pt", "rate", "lower", "upper", "prob")
save(gut_dstat_otu, file=paste0(dir_data_cleaning, "gut_sey_dstat_asv.RData"))
# Selection of core ASVs
gut_sey_core_otu <- gut_dstat_otu[gut_dstat_otu$disp > gut_dstat_otu$upper,]
gut_sey_core_otu <- na.exclude(gut_sey_core_otu)
gut_tax <- data.frame(seyrff_gut@tax_table@.Data)
gut_sey_core_otu$tax <- gut_tax[rownames(gut_tax) %in% row.names(gut_sey_core_otu),6]
gut_sey_core_otu$phylum <- gut_tax[rownames(gut_tax) %in% row.names(gut_sey_core_otu),2]
save(gut_sey_core_otu, file = paste0(dir_data_cleaning,"gut_sey_core_otu.Rdata"))

sey_gut_core <-prune_taxa(rownames(gut_sey_core_otu), seyrff_gut)
save(sey_gut_core, file = paste0(dir_data_cleaning, "sey_gut_core.RData"))

To blast the reads of the core, we need to generate a fasta file with the function writeXStringSet().

Composition of the core

Plot a treemap of the core thanks to the treemap() function for the main contributor of the core.

gut_core_order$Phylum = as.character(gut_core_order$Phylum) # Avoid error message with factor for next step
sort(table(factor(gut_core_order$Phylum)), T)
## 
##     Proteobacteria         Firmicutes     Planctomycetes      Bacteroidetes 
##                180                113                 40                 36 
##      Cyanobacteria    Verrucomicrobia       Fusobacteria       Spirochaetes 
##                 36                 35                 29                 21 
##        Tenericutes     Actinobacteria Kiritimatiellaeota    Deferribacteres 
##                 16                  6                  3                  2
gut_core_order[!gut_core_order$Phylum %in% c("Proteobacteria","Bacteroidetes","Cyanobacteria","Firmicutes","Planctomycetes", "Spirochaetes", "Verrucomicrobia","Fusobacteria","Tenericutes"),which(names(gut_core_order) == "Phylum", T)] <- "Other" #Change phylum to other for those not included in the list

group <-  gut_core_order$Phylum
subgroup <- gut_core_order$Order
value <- gut_core_order$Abundance

gut_core_treemap_data=data.frame(group,subgroup,value)

library(treemap)
gut_core_treemap <- treemap(gut_core_treemap_data,
                            index=c("group","subgroup"), vSize = "value", type = "index",
                            fontcolor.labels=c("white","black"),
                            fontsize.labels=c(12),bg.labels=c("transparent"),
                            fontface.labels=c(2,3),
                            border.col=c("black","white"), border.lwds=c(4,2), 
                            align.labels=list(c("center", "center"),c("left", "bottom")),
                            title="Seychelles Enteric Core Treemap",fontsize.title=12,
                            fontfamily.title ="serif")

and visualize the relative contribution of the different taxa (with the fill= argument for the level of the taxonomy you want represent) for the different reef condition or site with the argument x=.

Ex : The composition of the enteric core microbiome between reef fish families at phylum level.

Core ratio

To have a representation of the size of the core in the entire community, we can calculate the ratio of the sequences. This can give us informations on the inter individual dispersion : the higher the intra-species dispersion, the lower the size of the core and the larger the variable bacterial community of the compartment or species.

ratio_gut <- sum(sample_sums(sey_gut_core)) / sum(sample_sums(seyrff_gut))
percent(ratio_gut)
## [1] "62%"

Itol

In order to represent the taxa in the whole microbial description via Blast, we can then represent the source of our sequence (where they have already been described) in an interactive tree in Itol (Interactive Tree of Life). To do that, we need to transform our phylogenetic tree from the phyloseq object (obtained after an alignement in ARB here) in an xml output thanks to the write_xml() function.

devtools::install_github("USCBiostats/rphyloxml")
library(ape)
library(rphyloxml)
set.seed(12)
gut_tree <- sey_gut_core@phy_tree
gut_phyloxml <- write_phyloxml(gut_tree)
cat(as.character(gut_phyloxml))
xml2::write_xml(gut_phyloxml, "gut_phyloxml.xml")

Then, in order to add supplementary envdata (other than Blast, as a gradient, host species, geography etc….) you have to use a special template .txt for Itol. The function create_itol_files(env.xlsx) from the script table2itol.R is very useful to made automatically the templates from your env file. You are free to change the colors and shape as you want next. It faster than made a manually entry in the Itol website.


Part IVb: Algal core microbiome

back to top

We create a new folder for the algal microbiome and determine the core.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Algae/Core/")
dir.create(dir_data_cleaning, recursive = T)
load(paste0(dir_taxa_assign, "sey_algae.RData"))
load(paste0(dir_taxa_assign, "seyrff_algae.RData"))

Core determination

library(labdsv)
otu_table <- seyrff_algae@otu_table@.Data
abuoccplot_otu <- abuocc(otu_table)

## Press return for next plot

## Press return for next plot

## Do you want to identify individual species? Y/N : 
## Press return for next plot

## Do you want to identify individual plots? Y/N :
#sub_objects of abuocc objects
str(abuoccplot_otu)
## List of 3
##  $ spc.plt: Named int [1:29] 125 91 167 97 97 100 156 99 138 146 ...
##   ..- attr(*, "names")= chr [1:29] "C1-turf-A" "C1-turf-B" "C2-T-A" "C2-T-B" ...
##  $ plt.spc: Named int [1:2181] 1 12 1 2 1 1 1 1 8 1 ...
##   ..- attr(*, "names")= chr [1:2181] "ASV12005" "ASV1170" "ASV21768" "ASV3441" ...
##  $ mean   : Named num [1:2181] 65 26.9 32 10 3 ...
##   ..- attr(*, "names")= chr [1:2181] "ASV12005" "ASV1170" "ASV21768" "ASV3441" ...
##  - attr(*, "call")= language abuocc(comm = otu_table)
##  - attr(*, "comm")= chr [1:3754] "structure(list(ASV12005 = c(0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, " "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), ASV1170 = c(0, " "0, 49, 0, 0, 0, 16, 17, 0, 0, 0, 63, 0, 0, 31, 15, 0, 0, 0, 0, " "0, 0, 9, 14, 31, 49, 16, 13, 0), ASV21768 = c(0, 0, 0, 0, 0, " ...
##  - attr(*, "timestamp")= chr "Fri Jul 10 16:56:17 2020"
##  - attr(*, "class")= chr "abuocc"
# transform spc.plt vector into table in order to calculate specific richness
richness_otu <- data.frame(abuoccplot_otu$spc.plt)
# occurence of each OTU
otu_occurence <- data.frame(abuoccplot_otu$plt.spc)
mean.abun_otu <- colSums(otu_table)/otu_occurence
square_otu <- otu_table^2
ss_otu <- data.frame(colSums(square_otu))
# Variance calculation
variance_otu=ss_otu/otu_occurence-mean.abun_otu^2
disp_otu <- (variance_otu/mean.abun_otu)*otu_occurence
# IC calculation for Poisson distribution using Chi square distribution (value and formula within Zar p574)
library(epitools)
poisic_otu = pois.exact(otu_occurence, conf.level = 0.95)
algae_dstat_otu <- cbind(mean.abun_otu, disp_otu, otu_occurence, poisic_otu)
names(algae_dstat_otu) <- c("average","disp", "occurence", "x", "pt", "rate", "lower", "upper", "prob")
save(algae_dstat_otu, file=paste0(dir_data_cleaning, "algae_sey_dstat_asv.RData"))
# Selection of core ASVs
algae_sey_core_otu <- algae_dstat_otu[algae_dstat_otu$disp > algae_dstat_otu$upper,]
algae_sey_core_otu <- na.exclude(algae_sey_core_otu)
algae_tax <- data.frame(seyrff_algae@tax_table@.Data)
algae_sey_core_otu$tax <- algae_tax[rownames(algae_tax) %in% row.names(algae_sey_core_otu),6]
algae_sey_core_otu$phylum <- algae_tax[rownames(algae_tax) %in% row.names(algae_sey_core_otu),2]
save(algae_sey_core_otu, file = paste0(dir_data_cleaning,"algae_sey_core_otu.Rdata"))

sey_algae_core <-prune_taxa(rownames(algae_sey_core_otu), seyrff_algae)
save(sey_algae_core, file = paste0(dir_data_cleaning, "sey_algae_core.RData"))

To blast the reads of the core, we need to generate a fasta file with the function writeXStringSet().

Composition of the core

Plot a treemap of the core thanks to the treemap() function for the main contributor of the core.

algae_core_order$Phylum = as.character(algae_core_order$Phylum) # Avoid error message with factor for next step
sort(table(factor(algae_core_order$Phylum)), T)
## 
##  Proteobacteria   Bacteroidetes   Cyanobacteria  Planctomycetes Verrucomicrobia 
##             137              56              32              18              17 
##  Actinobacteria      Firmicutes    Fusobacteria     Chloroflexi 
##               4               2               2               1
algae_core_order[!algae_core_order$Phylum %in% 
                   c("Proteobacteria", "Bacteroidetes","Cyanobacteria","Verrucomicrobia","Planctomycetes"),which(names(algae_core_order) == "Phylum", T)] <- "Other" #Change phylum to other for those not included in the list

group <-  algae_core_order$Phylum
subgroup <- algae_core_order$Order
value <- algae_core_order$Abundance

algae_core_treemap_data=data.frame(group,subgroup,value)

library(treemap)
algae_core_treemap <- treemap(algae_core_treemap_data,
                            index=c("group","subgroup"), vSize = "value", type = "index",
                            fontcolor.labels=c("white","black"),
                            fontsize.labels=c(12),bg.labels=c("transparent"),
                            fontface.labels=c(2,3),
                            border.col=c("black","white"), border.lwds=c(4,2), 
                            align.labels=list(c("center", "center"),c("left", "bottom")),
                            title="Seychelles Algae Core Treemap",fontsize.title=12,
                            fontfamily.title ="serif")

and visualize the relative contribution of the different taxa (with the fill= argument for the level of the taxonomy you want represent) for the different reef condition or site with the argument x=.

Ex : The composition of the core algal microbiome between Mahe and Praslin at phylum level.

Core ratio

To have a representation of the size of the core in the entire community, we can calculate the ratio of the sequences. This can give us informations on the inter individual dispersion : the higher the intra-species dispersion, the lower the size of the core and the larger the variable bacterial community of the compartment or species.

ratio_algae <- sum(sample_sums(sey_algae_core)) / sum(sample_sums(seyrff_algae))
percent(ratio_algae)
## [1] "57%"

Part IVc: Global core and comparison

back to top

We create a new folder for the total core microbiome and compare both compatment in composition (LefSe) and in diversity (alpha and beta).

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Total Core/")
dir.create(dir_data_cleaning, recursive = T)
load(paste0(dir_taxa_assign, "sey_final.RData"))
load(paste0(dir_taxa_assign, "seyrff_final.RData"))

We use the otu tables of the enteric core and algal core to keep the ASVs names and subset them in the initial phyloseq object sey_final.

core_ASV <- unique(c(row.names(gut_sey_core_otu), row.names(algae_sey_core_otu)))
global_core <- subset_taxa(sey_final, taxa_names(sey_final) %in% core_ASV)
save(global_core, file = paste0(dir_data_cleaning, "global_core.RData"))

core_physeq_order <- global_core %>%
  tax_glom(taxrank = "Order") %>%                     # agglomerate at order level
  transform_sample_counts(function(x) {x/sum(x)} ) %>% # Transform to rel. abundance
  psmelt() %>%                                         # Melt to long format
  arrange(Order)
save(core_physeq_order , file = paste0(dir_data_cleaning, "core_physeq_order.RData"))

Now we can visualize easily by compartments the bacterial composition with the chosen taxa levels (e.g. Phylum here).

Alpha diversity comparisons

We compare the taxonomic diversity (observed richness and exp(shannon index) for the effective number of species (ENS)) between the normalized tables (478 ASVs normalized) of the enteric microbiome and epiphytes bacteria. Note that 478 was chosen because Lethrinus samples were very poor but essential for the comparisons between health status of the reef. Following the richness curves made higher during the Phyloseq process

##                   W stat      p-value
## Observed richness 2570.5 1.057345e-10
## Shannon (ENS)     2653.0 4.286702e-12

Beta diversity comparisons

Even we work on the core of normalized tables, we calculate the beta diversity ont the relative ASVs counts with the Bray-curtis distances with vegdist function from vegan package (Oksanen et al., 2019).

## [1] "Axis 1 : 9%"
## [1] "Axis 2 : 7%"
## [1] "Axis 3 : 5%"
## [1] "Axis 4 : 5%"

We then compare the beta diversity with the adonis function and test the dispersion between samples with betadisper.

library(pairwiseAdonis)
adonis(otu ~ Type, data = samp_data) # between gut, macroalgae and turf
## 
## Call:
## adonis(formula = otu ~ Type, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##            Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## Type        1     3.716  3.7163  8.6988 0.06458  0.001 ***
## Residuals 126    53.829  0.4272         0.93542           
## Total     127    57.545                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
pairwise.adonis(otu , samp_data$Type)
beta <- betadisper(otu, samp_data$Type)
permutest(beta)
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##            Df  Sum Sq  Mean Sq      F N.Perm Pr(>F)    
## Groups      1 0.22289 0.222895 84.163    999  0.001 ***
## Residuals 126 0.33369 0.002648                         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

LEfSe on compartments

In order to detect biomarkers proper to each compartment, we proceed to a Linear discriminant analysis on effect size (LEfSe) available on Galaxy. Here is the code to prepare the data input to proceed in Galaxy hub.

Proceed the “lefse_type_sey.txt” in a LEfse Galaxy and retrieve data “LDA Effect Size” with the associated “Plot LEfSe Results” in the LDA folder.You have to rename the former file “LDA_results” and run the following code.

library(plyr)
LDA_Effect_Size <- read.delim(paste0(dir_data_cleaning, "LDA_results"), header=FALSE)
LDA_gut <- subset(LDA_Effect_Size , LDA_Effect_Size$V3 == "Gut")
LDA_algae <- subset(LDA_Effect_Size , LDA_Effect_Size$V3 == "Algae")
LDA_type <- rbind(LDA_gut,LDA_algae)
LDA_phylum <- LDA_type$V1
names(LDA_phylum) <- ".Phylum.Class.Order.Family.Genus"
write.table(LDA_phylum, file=paste0(dir_data_cleaning, "LDA_phylum.txt"), sep="\t", row.names=F, col.names=F, quote=FALSE)
#paste the names(LDA_phylum) in excel then read it again.

library(readr)
LDA_phylum <- read_delim(paste0(dir_data_cleaning, "LDA_phylum.txt"),".", escape_double = FALSE, col_types = cols(X1 = col_skip()),trim_ws = TRUE)

#It will transform it in tabble and convert "." by separator 
LDA_phylum_type <- cbind(LDA_phylum , LDA_type[,2:5])
colnames(LDA_phylum_type) <- c(names(LDA_phylum)[1:5] , "LDA_res" , "Type" , "LDA_res2" , "sig")
write.table(LDA_phylum_type, file=paste0(dir_data_cleaning, "LDA_phylum_type.txt"), sep="\t", row.names=F, col.names=T, quote=FALSE)
LDA_phylum_type <- read_delim(paste0(dir_data_cleaning, "LDA_phylum_type.txt"),"\t", escape_double = FALSE, trim_ws = TRUE)
# Select your significativ value and taxa
LEFSE_sig <- subset(LDA_phylum_type, LDA_phylum_type$LDA_res2 >= 3)
LEFSE_sig_genus <- subset(LEFSE_sig, LEFSE_sig$Genus %in% as.character(na.exclude(LEFSE_sig$Genus)))
table(LEFSE_sig_genus$Type)
LEFSE_sig_genus_vec <- paste(LEFSE_sig_genus$Phylum, LEFSE_sig_genus$Class, LEFSE_sig_genus$Order, LEFSE_sig_genus$Family, LEFSE_sig_genus$Genus, sep = "|")

biomarkers <- paste(LEFSE_sig_genus$Order, LEFSE_sig_genus$Genus, sep = "|")
save(biomarkers, file = paste0(dir_data_cleaning, "biomarkers.RData"))

#sey_samp <- sey_compartment.genus@sam_data
#write.table(sey_samp, file=paste0(dir_data_cleaning, "sey_samp.txt"), sep="\t", row.names=F, col.names=T, quote=FALSE) # You need to numerate the tax3 name for the turf and sargassum samples and re-read it. 
sey_samp <- read_table2(paste0(dir_data_cleaning, "sey_samp.txt"))
sample_data(sey_compartment.genus)$tax3 <- sey_samp$tax3
levels(sample_data(sey_compartment.genus)$lineage) <- c("Algae", "Gut")

physeq_phylum <- sey_compartment.genus %>%    
  transform_sample_counts(function(x) {x/sum(x)} ) %>% # Transform to rel. abundance
  psmelt() %>%  
  filter(Abundance > 0) %>% # Melt to long format
  arrange(Genus)

physeq_phylum$Abundance <- physeq_phylum$Abundance/nrow(sample_data(sey_compartment.genus))

physeq_phylum$tax <- paste(physeq_phylum$Phylum, physeq_phylum$Class, physeq_phylum$Order, physeq_phylum$Family, physeq_phylum$Genus, sep = "|")
save(physeq_phylum, file= paste0(dir_data_cleaning, "physeq_phylum.RData"))
write.table(physeq_phylum ,file = paste0(dir_data_cleaning, "physeq_phylum.txt"), sep="\t",quote = F)

Diet_Pol_sey <- physeq_phylum
Diet_Pol_sey$tax <-  paste(Diet_Pol_sey$Order, Diet_Pol_sey$Genus, sep = "|")
length(physeq_phylum$tax)

df_sey <- Diet_Pol_sey[,c("lineage","Sample","tax","Abundance")]
colnames(df_sey) <- c("family","item","score","value")
save(df_sey, file = paste0(dir_data_cleaning, "df_sey.RData"))

Let’s organize our data to plot corresponding colours depending on the compartment.

load(paste0(dir_data_cleaning , "df_sey.RData"))
load(paste0(dir_data_cleaning , "biomarkers.RData"))

library(plyr)
print_biomarkers <- levels(factor(df_sey[df_sey$score %in% biomarkers,]$score)) # All biomarkers present in the sey.compartment_genus RData file
others <- levels(factor(df_sey[!df_sey$score %in% biomarkers,]$score)) # All taxa which are not biomarkers
df_sey[!df_sey$score %in% biomarkers,]$score <- "Z-Other" # Call them other (Z to figure at the end of the list)

# Some biomarkers are in common so Output the frequences.
freq_gut <- table(df_sey[df_sey$family == "Gut",]$score)/length(df_sey[df_sey$family == "Gut",]$score)*100 
freq_gut <- freq_gut[!names(freq_gut) == "Z-Other"]
freq_algae <- table(df_sey[df_sey$family == "Algae",]$score)/length(df_sey[df_sey$family == "Algae",]$score)*100 
freq_algae <- freq_algae[!names(freq_algae) == "Z-Other"]

# Keep the common biomarkers of the algae and gut and the respective frequencies in each compartment
biom_common <- names(freq_algae[which(names(freq_algae) %in% names(freq_gut))])
freq_gut_common <- as.data.frame(freq_gut[names(freq_gut) %in% biom_common])
freq_algae_common <- as.data.frame(freq_algae[names(freq_algae) %in% biom_common])
freq_common <- cbind(freq_gut_common, freq_algae_common$Freq)
colnames(freq_common) <- c("Biomarkers", "Freq_gut" ,"Freq_algae")
# Class the biomarkers in the compartment where the value is the higher
biom_gut_to_keep <- freq_common$Biomarkers[which(freq_common$Freq_gut > freq_common$Freq_algae, T)]
biom_algae_to_keep <- freq_common$Biomarkers[which(freq_common$Freq_algae > freq_common$Freq_gut, T)]
# See which are the biomarkers for the gut and which are the biomarkers for the algae
biom_gut <- levels(factor(df_sey[df_sey$family == "Gut",]$score))
biom_gut <- biom_gut[!biom_gut == "Z-Other"]
biom_gut <- biom_gut[!biom_gut %in% biom_algae_to_keep]
biom_algae <- levels(factor(df_sey[df_sey$family == "Algae",]$score))
biom_algae <- biom_algae[!biom_algae == "Z-Other"]
biom_algae <- biom_algae[!biom_algae %in% biom_gut_to_keep]

# Color choice
algae_colors <- c("darkgreen" , "darkkhaki", "darkolivegreen",
                  "darkolivegreen2","forestgreen","chartreuse",
                  "aquamarine","aquamarine3", "darkcyan",
                  "darkseagreen", "yellowgreen", "darkslategray",
                  "gold3", "gold4", "goldenrod",
                  "gold","palegreen4","chartreuse3",
                  "palegreen3", "seagreen3","palegoldenrod","yellow")
pie(rep(1, 22), col= algae_colors)

gut_colors <- c("brown", "brown1", "burlywood4",
                "chocolate","chocolate4", "coral2",
                "darksalmon","darkred","darkorchid4",
                "darkmagenta", "blueviolet","darkblue",
                "blue3", "deeppink4","deeppink")
pie(rep(1, 15), col= gut_colors)

polar_col <- c(algae_colors , gut_colors , 'Z_Other'="black")
# Add a prefix G (for gut) or A (for algae) in their respectiv biomarkers. In this way, they will be listed following 
# their respectiv compartment and no their names (easier for the add of the color in the ggplot)
df_sey[df_sey$score %in% biom_gut,]$score <- paste("G",df_sey[df_sey$score %in% biom_gut,]$score, sep= "-")
df_sey[df_sey$score %in% biom_algae,]$score <- paste("A",df_sey[df_sey$score %in% biom_algae,]$score, sep= "-")

We use the script of Ladroue et al.,(2012) to draw the histogram with the polarHistogram function available here.

source(paste0(dir_refdb, "polarHistogram.R"))
p <- polarHistogram(df_sey , familyLabel=T, innerRadius = 0.2, spaceFamily =7, circleProportion = 0.85)
p + ggplot2::scale_fill_manual(values= polar_col) +
  theme(legend.text = element_text(family = "serif", size = 3)) +
  theme(legend.position= "none") # to hide the legend because of the size

Conclusion

The microbial compositions between algae and the gut of reef fish is very different with many aerobic groups for the macroalgae and most of all anaerobic for the enteric core microbiomes. The blast analyses confirm the source of our ASVs which are mainly associated with animal host marine microbiomes. Their role have been described as important in the function of nutrition (e.g. Vibrionales, Clostridiales). A first observation remains of the very high and impressive variability between enteric core microbiomes. Now, we wonder what would be the origin of a such variability by testing the diet, the taxonomic effect and the effect of the environment as possible determinant of the variability of the microbiome.

Part V: Influence of the coral-macrolagal shift on microbial compositions

back to top

Our main issue is to determine if the shift coral-macroalgal in the Seychelles reefs would influence the composition of the core microbiome of their inhabitants. To test that, we will first analyse the influence on the environmental microbiome through the algae. Then, because a modification of the microbial environment would directly modify the microbiome of their consummer (here, the herbivores and indirectly the invertivores), we will test the effect of the shift on these both communities. We saw that core microbiome was highly variable between individuals. The taxonomic effect is already known to be a major determinant in the microbial composition in fishes. That is why, we will test the influence of the shift at different taxonomical levels (family, genus and species) when the sampling size was sufficient.

Part Va : Shift impact on the core microbiome of Algae

back to top

We will first create once again a new folder for the effect of the shift and other environmental parameters and test both on alpha and beta diversity.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Algae/Shift/")
dir.create(dir_data_cleaning, recursive = T)

Alpha diversity

load(paste0(dir_taxa_assign, "seyrff_algae.RData"))
box1 = plot_richness(seyrff_algae , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
box1$data$geomorpho <- str_replace_all(box1$data$geomorpho, c("macroalgal"= "M" , "coral"="C"))

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_algae_alpha_div =  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + 
  theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 18, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=12, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), 
              map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_algae_alpha_div

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat    p-value
## Observed richness     62 0.06348685
## Shannon (ENS)         60 0.05108988

Beta diversity

load(paste0(path, "/analyses/04_data_cleaning/Algae/Core/sey_algae_core.RData"))
core_algae_rel <- transform_sample_counts(sey_algae_core, function(x) x / sum(x) )
save(core_algae_rel , file = paste0(dir_data_cleaning, "core_algae_rel.RData"))

library(vegan)
library(ape)
otu <- vegdist(core_algae_rel@otu_table, method = "bray")
save(otu, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(otu)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_algae_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 18%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 15%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 8%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 6%"
palette = c("darkblue","darkred")
pcoa <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 3, shape = 17) +
  scale_color_manual(values = palette)+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=14), # remove x-axis labels
        axis.title.y = element_text(size=14), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank()) + theme(axis.title = element_text(family = "serif", size = 14), 
                                                   legend.text = element_text(size = 11, family = "serif"),
                                                   legend.title = element_text(size = 11,family = "serif")) +
  labs(colour = "Site", fill = "Reef")
pcoa

# _____ Permanovas and Betadisper  ------
samp_data <- read_delim(paste0(dir_data_cleaning,"samp_data.txt"),"\t", escape_double = FALSE, trim_ws = TRUE)

Let’s test the different microbial compositions in function of the geomorphology of the site (coral or macroalgal cover), the site and the substrata.

# Between geomorpho, site , substrat
adonis(otu ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## geomorpho  1    0.6960 0.69604  2.1204 0.07282  0.009 **
## Residuals 27    8.8628 0.32825         0.92718          
## Total     28    9.5589                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(otu ~ site, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## site       6    3.4182 0.56970   2.041 0.35759  0.001 ***
## Residuals 22    6.1407 0.27912         0.64241           
## Total     28    9.5589                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(otu ~ substrat, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ substrat, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## substrat   2    1.2421 0.62106  1.9416 0.12994  0.006 **
## Residuals 26    8.3168 0.31988         0.87006          
## Total     28    9.5589                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Because we had two types of macroalgae, and overall two different clades (brown macroalgae with the Sargassum and a green macroalgae with the turf)n, we tested if the environment would always plays a role inside a type of algae.

adonis(otu ~ type/geomorpho, strata= samp_data$type, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ type/geomorpho, data = samp_data, strata = samp_data$type) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## type            1    1.2689 1.26886  4.4608 0.13274  0.002 **
## type:geomorpho  2    1.1789 0.58947  2.0724 0.12333  0.002 **
## Residuals      25    7.1111 0.28444         0.74392          
## Total          28    9.5589                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(otu ~ type/site, strata= samp_data$type, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ type/site, data = samp_data, strata = samp_data$type) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## type       1    1.2689 1.26886  5.3586 0.13274  0.001 ***
## type:site  8    3.7911 0.47388  2.0013 0.39660  0.001 ***
## Residuals 19    4.4990 0.23679         0.47066           
## Total     28    9.5589                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(otu ~ type/substrat, strata= samp_data$type, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ type/substrat, data = samp_data, strata = samp_data$type) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##               Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## type           1    1.2689 1.26886  4.5678 0.13274  0.003 **
## type:substrat  3    1.6232 0.54108  1.9479 0.16982  0.003 **
## Residuals     24    6.6668 0.27778         0.69744          
## Total         28    9.5589                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(otu ~ type/island, strata= samp_data$type, data = samp_data)
## 
## Call:
## adonis(formula = otu ~ type/island, data = samp_data, strata = samp_data$type) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##             Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## type         1    1.2689 1.26886  4.3012 0.13274  0.017 *
## type:island  1    0.6200 0.61997  2.1016 0.06486  0.017 *
## Residuals   26    7.6701 0.29500         0.80240         
## Total       28    9.5589                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Part Vb : Shift impact on the enteric core microbiome of Reef fish

back to top

Herbivores

We have 3 families of herbivores : the scrappers Scaridae and the browsers Acanthuridae and Siganidae. Unfortunately, the only individuals present in the impacted shifted sites were three Scarus ghobban. Nevertheless, we tried to determine which were the other determinant in each components and test the effect of other environmental parameters.

Herbivorous community

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Herb/")
dir.create(dir_data_cleaning, recursive = T)

We need to subset from the sey_gut phyloseq object the herbivorous fishes.

herb_ps <- subset_samples(sey_gut, diet3 == "Herbivorous")
herb_ps <- prune_taxa(names(which(colSums(herb_ps@otu_table)>0)), herb_ps)
save(herb_ps, file = paste0(dir_data_cleaning, "herb_ps.RData"))
rff_herb <- prune_samples(sample_sums(herb_ps) >= min(sample_sums(herb_ps)) , herb_ps)
rff_herb <- rarefy_even_depth(herb_ps ,min(sample_sums(herb_ps)))
save(rff_herb , file = paste0(dir_data_cleaning, "rff_herb.RData"))
herb_core <- subset_samples(sey_gut_core, diet3 == "Herbivorous")
herb_core <- prune_taxa(names(which(colSums(herb_core@otu_table)>0)), herb_core)
save(herb_core, file = paste0(dir_data_cleaning, "herb_core.RData"))
Alpha and beta diversity
box1 = plot_richness(rff_herb , measures = c("Observed","Shannon") , color = "geomorpho")
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

palette = c("darkblue","darkred")
sey_herb_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE,
              textsize=5, color="black", family = "serif", vjust = 0.1)

sey_herb_alpha_div 

# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness  235.5 0.9248596
## Shannon (ENS)      234.0 0.8979202
core_herb_rel <- transform_sample_counts(herb_core, function(x) x / sum(x) )
save(core_herb_rel  , file = paste0(dir_data_cleaning, "core_herb_rel.RData"))
# _____ PCOA coda & permanova ------
matrix <- vegdist(core_herb_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_herb_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), quote = F, sep = "\t")
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 13%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 10%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 8%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 7%"
pcoa_herb <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho, shape = family), alpha = 0.7, size = 8) +
  scale_color_manual(values = palette)+
  scale_shape_manual(values = c(16,17,18))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_herb

Permanova on the only effect of the geomorpho but there is a lot of variability…

adonis(matrix ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## geomorpho  1    1.2963 1.29629  3.0248 0.06718  0.001 ***
## Residuals 42   17.9994 0.42856         0.93282           
## Total     43   19.2957                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

PERMANOVAs on the taxonomic effect between genus and species within families

adonis(matrix ~ family/genus/tax1, strata= samp_data$family, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ family/genus/tax1, data = samp_data,      strata = samp_data$family) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                   Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## family             2    2.7390 1.36952  3.8316 0.14195  0.001 ***
## family:genus       3    1.8726 0.62420  1.7464 0.09705  0.001 ***
## family:genus:tax1  7    3.6037 0.51481  1.4403 0.18676  0.009 ** 
## Residuals         31   11.0803 0.35743         0.57424           
## Total             43   19.2957                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

And between species/site , between species/geomorpho, and species/substrata inside families

adonis(matrix ~ tax1/site, strata= samp_data$family, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1/site, data = samp_data, strata = samp_data$family) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## tax1      12    8.2153 0.68461  2.1580 0.42576  0.001 ***
## tax1:site 11    4.7356 0.43051  1.3571 0.24542  0.011 *  
## Residuals 20    6.3447 0.31724         0.32882           
## Total     43   19.2957                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ tax1/geomorpho, strata= samp_data$family, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1/geomorpho, data = samp_data, strata = samp_data$family) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## tax1           12    8.2153 0.68461  1.9470 0.42576  0.001 ***
## tax1:geomorpho  2    0.8835 0.44175  1.2564 0.04579  0.134    
## Residuals      29   10.1968 0.35162         0.52845           
## Total          43   19.2957                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ tax1/substrat, strata= samp_data$family, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1/substrat, data = samp_data, strata = samp_data$family) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##               Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## tax1          12    8.2153 0.68461  2.0259 0.42576  0.002 **
## tax1:substrat  9    3.6458 0.40509  1.1987 0.18894  0.089 . 
## Residuals     22    7.4345 0.33793         0.38530          
## Total         43   19.2957                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

There is a significant effect of the taxonomic effect even at family level. To erase this effect, we focused our tests on Scaridae members.

Scaridae family

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Scaridae/")
dir.create(dir_data_cleaning, recursive = T)

scaridae_ps <- subset_samples(sey_gut, family == "Scaridae")
scaridae_ps <- prune_taxa(names(which(colSums(scaridae_ps@otu_table)>0)), scaridae_ps)
save(scaridae_ps, file = paste0(dir_data_cleaning, "scaridae_ps.RData"))
scaridaerff <- prune_samples(sample_sums(scaridae_ps) >= min(sample_sums(scaridae_ps)) , scaridae_ps)
scaridaerff <- rarefy_even_depth(scaridae_ps ,min(sample_sums(scaridae_ps)))
save(scaridaerff , file = paste0(dir_data_cleaning, "scaridaerff.RData"))
scar_core <- subset_samples(sey_gut_core, family == "Scaridae")
scar_core <- prune_taxa(names(which(colSums(scar_core@otu_table)>0)), scar_core)
save(scar_core, file = paste0(dir_data_cleaning, "scar_core.RData"))

Alpha and beta diversity

box1 = plot_richness(scaridaerff , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value
##  [1] 2.1957948 1.4266784 3.2637111 4.5718229 4.4840800 2.6830258 3.3967683
##  [8] 3.5768533 0.8209879 2.9114264 3.6864817 2.0008311 4.2034822 0.5042341
## [15] 4.1367648 2.8572218 2.8317726 4.0120393 4.5738187 2.7881697 2.7447567
## [22] 2.5988603
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

palette = c("darkblue","darkred")

sey_scaridae_alpha_div=ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_scaridae_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness   40.5 0.2710926
## Shannon (ENS)       42.0 0.2259740
scar_core_rel <- transform_sample_counts(scar_core, function(x) x / sum(x) )
save(scar_core_rel  , file = paste0(dir_data_cleaning, "scar_core_rel.RData"))
# _____ PCOA coda & permanova ------
matrix <- vegdist(scar_core_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))
# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(scar_core_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data , file = paste0(dir_data_cleaning, "samp_data.txt"), sep = "\t", quote = F)

hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 21%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 12%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 10%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 9%"
pcoa_scaridae <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = tax1, shape = site), alpha = 0.7, size = 8) +
  scale_shape_manual(values = c(15:19))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef", shape = "Site")
pcoa_scaridae

We will test the effect of the taxonomical levels (genus and species)

adonis(matrix ~ tax1,data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## tax1       7    3.7221 0.53173  1.4168 0.41465  0.012 *
## Residuals 14    5.2543 0.37531         0.58535         
## Total     21    8.9764                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ genus, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ genus, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## genus      2    1.2896 0.64480  1.5938 0.14367  0.006 **
## Residuals 19    7.6868 0.40457         0.85633          
## Total     21    8.9764                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Because there is a high taxonomic effect, we will “freeze” the genus effect to test the environmental effect (meaning that we test the substrate, geomorpho and site effect inside each genus). Even species have significantly different core microbial composition, We couldn’t test inside species level because we many species were only represented by one individual.

adonis(matrix ~ genus/tax1, strata = samp_data$genus, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ genus/tax1, data = samp_data, strata = samp_data$genus) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##            Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## genus       2    1.2896 0.64480  1.7181 0.14367  0.099 .
## genus:tax1  5    2.4325 0.48649  1.2962 0.27099  0.099 .
## Residuals  14    5.2543 0.37531         0.58535         
## Total      21    8.9764                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ genus/substrat, strata = samp_data$genus, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ genus/substrat, data = samp_data, strata = samp_data$genus) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## genus           2    1.2896 0.64480  1.7302 0.14367  0.011 *
## genus:substrat  3    1.7241 0.57470  1.5421 0.19207  0.011 *
## Residuals      16    5.9627 0.37267         0.66426         
## Total          21    8.9764                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ genus/site, strata = samp_data$genus, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ genus/site, data = samp_data, strata = samp_data$genus) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##            Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## genus       2    1.2896 0.64480  1.8528 0.14367  0.001 ***
## genus:site  5    2.8145 0.56289  1.6174 0.31354  0.001 ***
## Residuals  14    4.8723 0.34802         0.54279           
## Total      21    8.9764                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Scarus ghobban

Finally, the only herbivorous species which was in both type of reefs was the Scarus ghobban, who eats the epilithic part of the coral, searching for crustalose calcarous algae.

dir_data_cleaning <- paste0(path,"/analyses/04_data_cleaning/Fish/Shift/SCG/")
dir.create(dir_data_cleaning, recursive = T)

SCG <- subset_samples(sey_gut, tax1 == "Scarus ghobban")
SCG <- prune_taxa(names(which(colSums(SCG@otu_table)>0)), SCG)
save(SCG, file = paste0(dir_data_cleaning, "SCG.RData"))
SCGrff <- prune_samples(sample_sums(SCG) >= min(sample_sums(SCG)), SCG)
SCGrff <- rarefy_even_depth(SCGrff, sample.size = min(sample_sums(SCG)))
save(SCGrff, file = paste0(dir_data_cleaning, "SCGrff_ps.RData"))
core_SCG <- subset_samples(sey_gut_core, tax1 == "Scarus ghobban")
core_SCG <- prune_taxa(names(which(colSums(core_SCG@otu_table)>0)), core_SCG)
save(core_SCG, file = paste0(dir_data_cleaning, "core_SCG.RData"))
Alpha and beta diversity
box1 = plot_richness(SCGrff , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")
sey_SCG_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), 
              map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_SCG_alpha_div

MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness      8 0.6285714
## Shannon (ENS)          9 0.4000000
core_SCG_rel <- transform_sample_counts(core_SCG, function(x) x / sum(x) )
save(core_SCG_rel , file = paste0(dir_data_cleaning, "core_SCG_rel.RData"))
# _____ PCOA coda & permanova ------
matrix <- vegdist(core_SCG_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_SCG_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), sep= "\t", quote= F)
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 37%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 24%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 18%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 15%"
pcoa_SCG <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 8, shape = 16) +
  scale_color_manual(values = c("Darkblue","Darkred"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_SCG

We test the effect of the reef at host level.

adonis(matrix ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 5039
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1   0.70582 0.70582  1.9293 0.27843  0.106
## Residuals  5   1.82916 0.36583         0.72157       
## Total      6   2.53498                 1.00000

Even if we can’t test the effect of the reef on the other herbivores family, we can test the site, island and substrat effect on the Siganidae.

Siganidae family

Beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Siganidae/")
dir.create(dir_data_cleaning, recursive = T)

siganidae_ps <- subset_samples(sey_gut, family == "Siganidae")
siganidae_ps <- prune_taxa(names(which(colSums(siganidae_ps@otu_table)>0)), siganidae_ps)
save(siganidae_ps, file = paste0(dir_data_cleaning, "siganidae_ps.RData"))
siganidaerff <- prune_samples(sample_sums(siganidae_ps) >= min(sample_sums(siganidae_ps)) , siganidae_ps)
siganidaerff <- rarefy_even_depth(siganidae_ps ,min(sample_sums(siganidae_ps)))
save(siganidaerff , file = paste0(dir_data_cleaning, "siganidaerff.RData"))
sig_core <- subset_samples(sey_gut_core, family == "Siganidae")
sig_core <- prune_taxa(names(which(colSums(sig_core@otu_table)>0)), sig_core)
save(sig_core, file = paste0(dir_data_cleaning, "sig_core.RData"))
sig_core_rel <- transform_sample_counts(sig_core, function(x) x / sum(x) )
save(sig_core_rel  , file = paste0(dir_data_cleaning, "sig_core_rel.RData"))

matrix <- vegdist(sig_core_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))
# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(sig_core_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), quote = F, sep = "\t")
hull <- cbind(pcoa_coord, samp_data)

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 23%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 15%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 12%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 10%"
pcoa_sig <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = tax1, shape = site),alpha = 0.7, size = 8) +
  scale_shape_manual(values = c(18,15,16,17))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Species", shape =  "Site")
pcoa_sig

adonis(matrix ~ tax1,data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## tax1       2    1.1712 0.58561  1.7057 0.19593  0.019 *
## Residuals 14    4.8066 0.34333         0.80407         
## Total     16    5.9778                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ island, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ island, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## island     1    0.3801 0.38012  1.0186 0.06359  0.393
## Residuals 15    5.5977 0.37318         0.93641       
## Total     16    5.9778                 1.00000
adonis(matrix ~ site, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## site       3    1.4130 0.47100  1.3413 0.23637  0.084 .
## Residuals 13    4.5648 0.35114         0.76363         
## Total     16    5.9778                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ substrat, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ substrat, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## substrat   1    0.3801 0.38012  1.0186 0.06359  0.419
## Residuals 15    5.5977 0.37318         0.93641       
## Total     16    5.9778                 1.00000

Carnivores

Carnivorous community

Now let’s see the influence of the shift on the carnivores which were more ubiquitous between sites and reef conditions.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Carnivores/")
dir.create(dir_data_cleaning, recursive = T)

We need to subset from the sey_gut phyloseq object the carnivorous fishes.

carn_ps <- subset_samples(sey_gut, diet3 == "Carnivorous")
carn_ps <- prune_taxa(names(which(colSums(carn_ps@otu_table)>0)), carn_ps)
save(carn_ps, file = paste0(dir_data_cleaning, "carn_ps.RData"))
rff_carn <- prune_samples(sample_sums(carn_ps) >= min(sample_sums(carn_ps)) , carn_ps)
rff_carn <- rarefy_even_depth(carn_ps ,min(sample_sums(carn_ps)))
save(rff_carn , file = paste0(dir_data_cleaning, "rff_carn.RData"))
carn_core <- subset_samples(sey_gut_core, diet3 == "Carnivorous")
carn_core <- prune_taxa(names(which(colSums(carn_core@otu_table)>0)), carn_core)
save(carn_core, file = paste0(dir_data_cleaning, "carn_core.RData"))
Alpha and beta diversity
box1 = plot_richness(rff_carn , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_carn_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_carn_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness    326 0.6753113
## Shannon (ENS)        363 0.8252230
core_carn_rel <- transform_sample_counts(carn_core, function(x) x / sum(x) )
save(core_carn_rel  , file = paste0(dir_data_cleaning, "core_carn_rel.RData"))

matrix <- vegdist(core_carn_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_carn_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), quote = F, sep = "\t")
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 10%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 9%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 7%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 6%"
pcoa_carn <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho, shape = family), alpha = 0.7, size = 8) +
  scale_color_manual(values = palette)+
  scale_shape_manual(values =c(15:18, 8))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef", shape= "Family")
pcoa_carn

We tested first the influence of the environment

adonis(matrix ~ island,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ island, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## island     1    0.5651 0.56509  1.3071 0.02499  0.097 .
## Residuals 51   22.0484 0.43232         0.97501         
## Total     52   22.6135                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ geomorpho,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1    0.4216 0.42162 0.96895 0.01864    0.5
## Residuals 51   22.1919 0.43513         0.98136       
## Total     52   22.6135                 1.00000
adonis(matrix ~ site,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## site       6    2.9559 0.49265  1.1528 0.13071  0.061 .
## Residuals 46   19.6576 0.42734         0.86929         
## Total     52   22.6135                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ substrat,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ substrat, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## substrat   2    0.8248 0.41239 0.94633 0.03647  0.598
## Residuals 50   21.7887 0.43577         0.96353       
## Total     52   22.6135                 1.00000

And then the taxonomic effect

adonis(matrix ~ family,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ family, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)  
## family     4    2.2134 0.55335   1.302 0.09788  0.015 *
## Residuals 48   20.4001 0.42500         0.90212         
## Total     52   22.6135                 1.00000         
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
adonis(matrix ~ family/genus/tax1 ,  data =samp_data)
## 
## Call:
## adonis(formula = matrix ~ family/genus/tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                   Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)   
## family             4    2.2134 0.55335  1.3342 0.09788  0.010 **
## family:genus       7    3.1202 0.44574  1.0747 0.13798  0.159   
## family:genus:tax1 10    4.4224 0.44224  1.0663 0.19557  0.184   
## Residuals         31   12.8575 0.41476         0.56858          
## Total             52   22.6135                 1.00000          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Lutjanidae family

Alpha and beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Lutjanidae/")
dir.create(dir_data_cleaning, recursive = T)

lutj_ps <- subset_samples(sey_gut, family == "Lutjanidae")
lutj_ps <- prune_taxa(names(which(colSums(lutj_ps@otu_table)>0)), lutj_ps)
save(lutj_ps, file = paste0(dir_data_cleaning, "lutj_ps.RData"))
rff_lutj <- prune_samples(sample_sums(lutj_ps) >= min(sample_sums(lutj_ps)) , lutj_ps)
rff_lutj <- rarefy_even_depth(lutj_ps ,min(sample_sums(lutj_ps)))
save(rff_lutj , file = paste0(dir_data_cleaning, "rff_lutj.RData"))
core_lutj <- subset_samples(sey_gut_core, family == "Lutjanidae")
core_lutj <- prune_taxa(names(which(colSums(core_lutj@otu_table)>0)), core_lutj)
save(core_lutj, file = paste0(dir_data_cleaning, "core_lutj.RData"))

# __ Alpha diversity ----
box1 = plot_richness(rff_lutj , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_lutj_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")
sey_lutj_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness     13 0.1742945
## Shannon (ENS)         16 0.3449883
core_lutj_rel <- transform_sample_counts(core_lutj, function(x) x / sum(x) )
save(core_lutj_rel  , file = paste0(dir_data_cleaning, "core_lutj_rel.RData"))
# _____ PCOA coda & permanova ------
library(vegan)
library(ape)
matrix <- vegdist(core_lutj_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_lutj_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), sep = "\t", quote = F)

hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 23%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 14%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 11%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 10%"
pcoa_lutj <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 8, shape = 16) +
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  scale_colour_manual(values= palette)+
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_lutj

The sampling size for the members of the Lutjanidae family was enough to test several parameters as effect of species, genus, geomorphology of the reef, site and substrat.

adonis(matrix ~ tax1,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## tax1       4    1.8202 0.45505  1.1221 0.33277  0.229
## Residuals  9    3.6496 0.40552         0.66723       
## Total     13    5.4698                 1.00000
adonis(matrix ~ genus,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ genus, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## genus      1    0.4498 0.44982  1.0753 0.08224  0.323
## Residuals 12    5.0200 0.41833         0.91776       
## Total     13    5.4698                 1.00000
adonis(matrix ~ geomorpho,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1    0.5446 0.54463   1.327 0.09957  0.134
## Residuals 12    4.9252 0.41043         0.90043       
## Total     13    5.4698                 1.00000
adonis(matrix ~ site,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## site       4    1.4953 0.37382 0.84648 0.27337  0.829
## Residuals  9    3.9746 0.44162         0.72663       
## Total     13    5.4698                 1.00000
adonis(matrix ~ substrat,  data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ substrat, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## substrat   2    0.6466 0.32332 0.73738 0.11822  0.897
## Residuals 11    4.8232 0.43847         0.88178       
## Total     13    5.4698                 1.00000
beta_reef <- betadisper(matrix, samp_data$tax1)
permutest(beta_reef)
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##           Df  Sum Sq  Mean Sq      F N.Perm Pr(>F)   
## Groups     4 0.52105 0.130262 5.5167    999  0.009 **
## Residuals  9 0.21251 0.023612                        
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

In this family, we could test at host level the effect on the species Aprion virescens.

Aprion virescens

Alpha and beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/APV/")
dir.create(dir_data_cleaning, recursive = T)

APV <- subset_samples(sey_gut, tax1 == "Aprion virescens")
APV <- prune_taxa(names(which(colSums(APV@otu_table)>0)), APV)
save(APV, file = paste0(dir_data_cleaning, "APV.RData"))
APVrff <- prune_samples(sample_sums(APV) >= min(sample_sums(APV)), APV)
APVrff <- rarefy_even_depth(APVrff, sample.size = min(sample_sums(APV)))
save(APVrff, file = paste0(dir_data_cleaning, "APVrff_ps.RData"))
core_APV <- subset_samples(sey_gut_core, tax1 == "Aprion virescens")
core_APV <- prune_taxa(names(which(colSums(core_APV@otu_table)>0)),core_APV)
save(core_APV, file = paste0(dir_data_cleaning, "core_APV.RData"))
box1 = plot_richness(APVrff , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_APV_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 20, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=8, color="black", family = "serif")

sey_APV_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness      4 0.6285714
## Shannon (ENS)          7 0.8571429

Lethrinidae

Alpha and beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/Lethrinus/")
dir.create(dir_data_cleaning, recursive = T)

sey_leth <- subset_samples(sey_gut, family == "Lethrinidae")
sey_leth <- prune_taxa(names(which(colSums(sey_leth@otu_table)>0)), sey_leth)
save(sey_leth, file = paste0(dir_data_cleaning, "sey_leth.RData"))
rff_leth <- prune_samples(sample_sums(sey_leth) >= min(sample_sums(sey_leth)) , sey_leth)
rff_leth <- rarefy_even_depth(rff_leth ,min(sample_sums(rff_leth)))
save(rff_leth , file = paste0(dir_data_cleaning, "rff_leth.RData"))
core_leth <- subset_samples(sey_gut_core, genus == "Lethrinus")
core_leth <- prune_taxa(names(which(colSums(core_leth@otu_table)>0)),core_leth)
save(core_leth, file = paste0(dir_data_cleaning, "core_leth.RData"))
box1 = plot_richness(rff_leth , measures = c("Observed","Shannon") , color = "geomorpho")
box1$data
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_lethr_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_lethr_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness     84 0.9593578
## Shannon (ENS)         83 1.0000000
core_leth_rel <- transform_sample_counts(core_leth, function(x) x / sum(x) )
save(core_leth_rel  , file = paste0(dir_data_cleaning, "core_leth_rel.RData"))
# _____ PCOA coda & permanova ------
library(vegan)
library(ape)
matrix <- vegdist(core_leth_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_leth_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), quote = F, sep = "\t")

hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 14%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 9%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 8%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 7%"
pcoa_lethr <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 8, shape = 16) +
  scale_color_manual(values = c("Darkblue","Darkred"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_lethr

adonis(matrix ~ tax1 , data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## tax1       5    2.2512 0.45024  1.0924 0.21452  0.191
## Residuals 20    8.2430 0.41215         0.78548       
## Total     25   10.4943                 1.00000
adonis(matrix ~ island, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ island, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## island     1    0.4864 0.48645  1.1666 0.04635  0.185
## Residuals 24   10.0078 0.41699         0.95365       
## Total     25   10.4943                 1.00000
adonis(matrix ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1    0.4896 0.48960  1.1745 0.04665  0.182
## Residuals 24   10.0047 0.41686         0.95335       
## Total     25   10.4943                 1.00000
adonis(matrix ~ substrat, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ substrat, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## substrat   2    0.8541 0.42706  1.0189 0.08139  0.412
## Residuals 23    9.6401 0.41914         0.91861       
## Total     25   10.4943                 1.00000
adonis(matrix ~ site, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## site       5    2.3167 0.46334  1.1332 0.22076  0.108
## Residuals 20    8.1775 0.40888         0.77924       
## Total     25   10.4943                 1.00000

Inside this family, we are able to test two different species : Lethrinus mahsena and Lethrinus enigmaticus.

Lethrinus mahsena

Alpha and beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/LEM/")
dir.create(dir_data_cleaning, recursive = T)

LEM <- subset_samples(sey_gut, tax1 == "Lethrinus mahsena")
LEM <- prune_taxa(names(which(colSums(LEM@otu_table)>0)), LEM)
save(LEM, file = paste0(dir_data_cleaning, "LEM.RData"))
LEMrff <- prune_samples(sample_sums(LEM) >= min(sample_sums(LEM)) , LEM)
LEMrff <- rarefy_even_depth(LEMrff ,min(sample_sums(LEMrff)))
save(LEMrff , file = paste0(dir_data_cleaning, "LEMrff.RData"))
core_LEM <- subset_samples(sey_gut_core, tax1 == "Lethrinus mahsena")
core_LEM <- prune_taxa(names(which(colSums(core_LEM@otu_table)>0)), core_LEM)
save(core_LEM, file = paste0(dir_data_cleaning, "core_LEM.RData"))
box1 = plot_richness(LEMrff , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_LEM_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_LEM_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness      8 0.6475058
## Shannon (ENS)          9 0.8333333
core_LEM_rel <- transform_sample_counts(core_LEM, function(x) x / sum(x) )
save(core_LEM_rel  , file = paste0(dir_data_cleaning, "core_LEM_rel.RData"))
# _____ PCOA coda & permanova ------
library(vegan)
library(ape)
matrix <- vegdist(core_LEM_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_LEM_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 20%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 16%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 13%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 12%"
pcoa_LEM <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 8, shape = 16) +
  scale_color_manual(values = c("darkblue","darkred"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_LEM

For this species, we can only test the geomorpho and site effect.

adonis(matrix ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1    0.4824 0.48240  1.1014 0.12102  0.259
## Residuals  8    3.5038 0.43797         0.87898       
## Total      9    3.9862                 1.00000
adonis(matrix ~ site, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ site, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## site       2    0.9778 0.48888  1.1375 0.24529  0.181
## Residuals  7    3.0084 0.42977         0.75471       
## Total      9    3.9862                 1.00000

Lethrinus enigmaticus

Alpha and beta diversity
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Shift/LEE/")
dir.create(dir_data_cleaning, recursive = T)

LEE <- subset_samples(sey_gut, tax1 == "Lethrinus mahsena")
LEE <- prune_taxa(names(which(colSums(LEE@otu_table)>0)), LEE)
save(LEE, file = paste0(dir_data_cleaning, "LEE.RData"))
LEErff <- prune_samples(sample_sums(LEE) >= min(sample_sums(LEE)) , LEE)
LEErff <- rarefy_even_depth(LEErff ,min(sample_sums(LEErff)))
save(LEErff , file = paste0(dir_data_cleaning, "LEErff.RData"))
core_LEE <- subset_samples(sey_gut_core, tax1 == "Lethrinus mahsena")
core_LEE <- prune_taxa(names(which(colSums(core_LEE@otu_table)>0)), core_LEE)
save(core_LEE, file = paste0(dir_data_cleaning, "core_LEE.RData"))
box1 = plot_richness(LEErff , measures = c("Observed","Shannon") , color = "geomorpho")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable)= c("Observed richness","Shannon (ENS)")
levels(box1$data$geomorpho) = c("C" , "M")

library(ggsignif)
library(ggplot2)
palette = c("darkblue","darkred")

sey_LEE_alpha_div=  ggplot(box1$data, aes(x = factor(geomorpho) , y = value, color = factor(geomorpho))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) +
  scale_colour_manual(values= palette) + theme_bw()+
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 24, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free") +
  geom_signif(comparisons = list(c("C", "M")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")

sey_LEE_alpha_div 

# ____ Test MW ----
library(pgirmess)
# Does exist differences in diversity between types of host? 
# ____________ Observed richness MW 
MW.obs = wilcox.test(box1$data$value[box1$data$variable=="Observed richness"]~box1$data$geomorpho[box1$data$variable=="Observed richness"])
MW.obs = cbind(MW.obs$statistic, MW.obs$p.value)
# ____________ Shannon number MW 
MW.shannon = wilcox.test(box1$data$value[box1$data$variable=="Shannon (ENS)"]~box1$data$geomorpho[box1$data$variable=="Shannon (ENS)"])
MW.shannon =cbind(MW.shannon$statistic, MW.shannon$p.value)
# ____________ All computed 
MW.test <- rbind(MW.obs, MW.shannon)
rownames(MW.test) = c("Observed richness","Shannon (ENS)")
colnames(MW.test) = c('W stat' , 'p-value')
MW.test
##                   W stat   p-value
## Observed richness      8 0.6666667
## Shannon (ENS)          9 0.8333333
core_LEE_rel <- transform_sample_counts(core_LEE, function(x) x / sum(x) )
save(core_LEE_rel  , file = paste0(dir_data_cleaning, "core_LEE_rel.RData"))
# _____ PCOA coda & permanova ------
library(vegan)
library(ape)
matrix <- vegdist(core_LEE_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_LEE_rel))
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 20%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 16%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 13%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 12%"
pcoa_LEE <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = geomorpho), alpha = 0.7, size = 8, shape = 16) +
  scale_color_manual(values = c("darkblue","darkred"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Reef")
pcoa_LEE

For this species, we can only test the geomorpho and site effect.

adonis(matrix ~ geomorpho, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ geomorpho, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)
## geomorpho  1    0.4824 0.48240  1.1014 0.12102  0.308
## Residuals  8    3.5038 0.43797         0.87898       
## Total      9    3.9862                 1.00000

Conclusion

Finally, it seems that the shift coral - macroalgae doesn’t impact the enteric core microbiome of the reef fish while the core epiphyte is influenced by the environmental parameters as geomorphology, substrat and location. This has already been described in other studies relating on the microbiomes of algae ( Serebryakova et al., 2018). A very weak signal is detected for the herbivores Scarus ghobban and would have maybe been significant with a higher sampling size. Moreover, the observed changes in the diversity and bacterial compositions associated to primary producers with Sargassum and turf algae, which hold a pivotal role as major nutritional resources for Siganidae and Acanthuridae ( Cheal et al., 2010), let us think to further consequences on the enteric microbial compositions of these latter. Nowadays, It is quite admitted that diet is one of the strongest determinant of fish enteric microbiomes. Moreover, some studies in aquaculture have demonstrated that a modification of the food quality markedly influences the variability and diversity of enteric microbiomes ( Butt et al., 2019). Also, as demonstrated in zebrafish hosts, the absence or decreasing availability of food may cause a stress and act as an important factor of the variability of the enteric microbiome even dysbiosis ( Cantas et al., 2012). The resistence of the enteric microbiome against environmental perturbation (modification/absence of the diet because of habitat fragmentation or anthropogenization) has been observed in non human primate in Africa where the species identity remained the strongest determinant ( McCord et al., 2014). In our case, what are thus the stronger determinants that influence the enteric core microbiome?

Part VI: Other drivers of enteric microbial communities

back to top

The diet and the taxonomy are known to be major drivers of the microbial assemblage in the gut of fishes. We have seen previously some effect at different scale. Here, we will describe and determine which are the differences between the diversity of the differnt types of diet and families and try to detect some biomarkers which could play a functional role in the nutrition of the reef fish.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Core/A_div/")
dir.create(dir_data_cleaning)

Let’s see at granulous scale of diet :Herbivorous vs carnivorous with the 3 omnivorous fishes considered as herbivorous.

Alpha and beta diversity

# ____ Shannon (ENS), Faith PD and LCBD ----
levels(sample_data(seyrff_gut)$diet3)[3] = "Herbivorous"
box1 = plot_richness(seyrff_gut , measures = c("Observed","Shannon") , color = "diet3")
# ____ Shannon index (ENS)
box1$data[box1$data$variable == "Shannon",]$value = exp(box1$data[box1$data$variable == "Shannon",]$value)
levels(box1$data$variable) = c("Observed richness", "Shannon (ENS)")

library(ggsignif)
library(ggplot2)
palette = c("darkred" , "darkgreen")

sey_alpha_div_diet =  ggplot(box1$data, aes(x = factor(diet3) , y = value, color = factor(diet3))) + 
  geom_jitter(position = position_jitter(width = .20), alpha = 0.5, size = 3) + theme_bw() +
  geom_boxplot(alpha=0.1, outlier.colour = NA) + 
  scale_color_manual(values = palette)+
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text = element_text(family = "serif",size = 14), 
        axis.text.x = element_text(family = "serif",size = 15, angle = 0),
        axis.text.y = element_text(family = "serif",size = 20, angle = 0),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position="none",
        strip.text.x = element_text(size=15, family = "serif")) + 
  geom_signif(comparisons = list(c("Carnivorous", "Herbivorous")), map_signif_level = TRUE, textsize=5, color="black", family = "serif")+
  facet_wrap( ~ variable, nrow=1, ncol=5, scales = "free")
sey_alpha_div_diet

# ____ Dunn test ----
library(pgirmess)
library(dunn.test)
# Does exist differences in diversity between diets? 
# ____________ Observed dunn 
dunn.test(box1$data$value[box1$data$variable=="Observed richness"],box1$data$diet1[box1$data$variable=="Observed richness"], method = "bonferroni")
##   Kruskal-Wallis rank sum test
## 
## data: x and group
## Kruskal-Wallis chi-squared = 13.507, df = 4, p-value = 0.01
## 
## 
##                            Comparison of x by group                            
##                                  (Bonferroni)                                  
## Col Mean-|
## Row Mean |         FC          H         HD         MI
## ---------+--------------------------------------------
##        H |  -3.125502
##          |    0.0089*
##          |
##       HD |  -2.664975  -0.559770
##          |     0.0385     1.0000
##          |
##       MI |  -2.415064   1.242383   1.197258
##          |     0.0787     1.0000     1.0000
##          |
##       OM |  -2.591145  -1.194984  -0.760599  -1.579624
##          |     0.0478     1.0000     1.0000     0.5710
## 
## alpha = 0.05
## Reject Ho if p <= alpha/2
# ____________ Shannon number dunn 
dunn.test(box1$data$value[box1$data$variable=="Shannon (ENS)"],box1$data$diet1[box1$data$variable=="Shannon (ENS)"], method = "bonferroni")
##   Kruskal-Wallis rank sum test
## 
## data: x and group
## Kruskal-Wallis chi-squared = 13.0985, df = 4, p-value = 0.01
## 
## 
##                            Comparison of x by group                            
##                                  (Bonferroni)                                  
## Col Mean-|
## Row Mean |         FC          H         HD         MI
## ---------+--------------------------------------------
##        H |  -3.240358
##          |    0.0060*
##          |
##       HD |  -2.271655   0.009037
##          |     0.1155     1.0000
##          |
##       MI |  -2.377953   1.495953   0.752121
##          |     0.0870     0.6733     1.0000
##          |
##       OM |  -2.474232  -1.010313  -0.902549  -1.471990
##          |     0.0668     1.0000     1.0000     0.7051
## 
## alpha = 0.05
## Reject Ho if p <= alpha/2
dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Core/B_div/")
dir.create(dir_data_cleaning)

core_gut_rel <- transform_sample_counts(sey_gut_core, function(x) x / sum(x) )
save(core_gut_rel  , file = paste0(dir_data_cleaning, "core_gut_rel.RData"))
# _____ PCOA coda & permanova ------
library(vegan)
library(ape)
matrix <- vegdist(core_gut_rel@otu_table, method = "bray")
save(matrix, file = paste0(dir_data_cleaning, "beta_matrices.RData"))
pcoa.sub <- pcoa(matrix)
save(pcoa.sub, file = paste0(dir_data_cleaning, "pcoa.values.RData"))

# Contruction of the table for graphic 
pcoa_coord <- pcoa.sub$vectors[,1:3]
# _____ PCOA Plot-----
library(stringr)
samp_data <- data.frame(sample_data(core_gut_rel))
levels(samp_data$diet3) <- c("Carnivorous", "Herbivorous","Herbivorous")
save(samp_data,file = paste0(dir_data_cleaning, "samp_data.RData"))
#write.table(samp_data, file = paste0(dir_data_cleaning, "samp_data.txt"), quote = F, sep = "\t")
hull <- cbind(pcoa_coord, samp_data)
hull$geomorpho <- str_replace_all(hull$geomorpho, c("macroalgal"= "M" , "coral"="C"))

# What is the percentage of the explicative variance? 
paste("Axis 1 :",percent(pcoa.sub$values$Relative_eig[1])) 
## [1] "Axis 1 : 9%"
paste("Axis 2 :",percent(pcoa.sub$values$Relative_eig[2])) 
## [1] "Axis 2 : 7%"
paste("Axis 3 :",percent(pcoa.sub$values$Relative_eig[3]))
## [1] "Axis 3 : 6%"
paste("Axis 4 :",percent(pcoa.sub$values$Relative_eig[4]))
## [1] "Axis 4 : 6%"
pcoa_diet1 <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = diet1), alpha = 0.7, size = 8) +
  scale_color_manual(values =  c("Darkred", "Darkgreen","Darkkhaki","Darkorange","Darkorchid"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Diet")
pcoa_diet1

pcoa_diet3 <- ggplot() +
  geom_hline(yintercept=0, colour="lightgrey", linetype = 2) +
  geom_vline(xintercept=0, colour="lightgrey", linetype = 2) +
  geom_point(data = hull, aes(x=Axis.1, y=Axis.2, color = diet3), alpha = 0.7, size = 8) +
  scale_color_manual(values = c("Darkred", "Darkgreen"))+
  xlab(paste("PCo1 (", round(pcoa.sub$values$Relative_eig[1]*100, 1), "%)")) +
  ylab(paste("PCo2 (", round(pcoa.sub$values$Relative_eig[2]*100, 1), "%)"))  +
  theme_bw() +
  coord_equal() +
  theme(axis.title.x = element_text(size=20, family = "serif"), # remove x-axis labels
        axis.title.y = element_text(size=20 , family = "serif"),
        axis.text.x = element_text(size = 18, family = "serif"), 
        axis.text.y = element_text(size = 18, family = "serif"),
        legend.text = element_text(size = 16, family = "serif"),
        legend.title = element_text(size = 16,family = "serif"), # remove y-axis labels
        panel.background = element_blank(),
        panel.grid.major = element_blank(),  #remove major-grid labels
        panel.grid.minor = element_blank(),  #remove minor-grid labels
        plot.background = element_blank(),
        axis.title = element_text(size = 25))+
  labs(colour = "Diet")
pcoa_diet3

The herbivores and carnivores seem to compose two different clusters well defined. Let’s test the influence of the diet:

# Between diets
adonis(matrix ~ diet1, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ diet1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## diet1      4     3.479 0.86983  2.0004 0.07845  0.001 ***
## Residuals 94    40.874 0.43483         0.92155           
## Total     98    44.353                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The taxonomy can also play a role in the determination of the microbial composition, so what is the effect of the taxonomy?

# Between families
adonis(matrix ~ tax1, data = samp_data)
## 
## Call:
## adonis(formula = matrix ~ tax1, data = samp_data) 
## 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##           Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## tax1      35    19.986 0.57104  1.4764 0.45062  0.001 ***
## Residuals 63    24.367 0.38677         0.54938           
## Total     98    44.353                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

To test the effect of the diet inside a taxonomic level, we freeze the diet and see what is the effect of the family, and inside the family, the effect of the genus, and inside a genus, the effect of a species. Actually, we tested the effect between species and genus, sharing the same family, with the effect of the diet blocked (in case of different diet inside family which can occur between piscivorous and invertivores in the Lutjanidae family).

adonis(matrix ~  diet3/family / genus / tax1, strata = samp_data$diet3, data = samp_data) 
## 
## Call:
## adonis(formula = matrix ~ diet3/family/genus/tax1, data = samp_data,      strata = samp_data$diet3) 
## 
## Blocks:  strata 
## Permutation: free
## Number of permutations: 999
## 
## Terms added sequentially (first to last)
## 
##                         Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
## diet3                    1     1.613 1.61348  4.1716 0.03638  0.001 ***
## diet3:family             7     5.354 0.76487  1.9776 0.12071  0.001 ***
## diet3:family:genus      10     4.993 0.49928  1.2909 0.11257  0.001 ***
## diet3:family:genus:tax1 17     8.026 0.47212  1.2207 0.18096  0.002 ** 
## Residuals               63    24.367 0.38677         0.54938           
## Total                   98    44.353                 1.00000           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

LEfSe between diet

To detect now biomarkers in herbivores and carnivores, we apply an discriminant analysis with LEfsE analysis.

Proceed the “lefse_type_sey.txt” in a LEfse Galaxy and retrieve data “LDA Effect Size” with the associated “Plot LEfSe Results” in the LDA folder.You have to rename the former file “LDA_results” and run the following code.

library(plyr)
LDA_Effect_Size <- read.delim(paste0(dir_data_cleaning, "LDA_results"), header=FALSE)
LDA_carn <- subset(LDA_Effect_Size , LDA_Effect_Size$V3 == "Carnivorous")
LDA_herb <- subset(LDA_Effect_Size , LDA_Effect_Size$V3 == "Herbivorous")
LDA_diet <- rbind(LDA_carn,LDA_herb)
LDA_phylum <- LDA_diet$V1
names(LDA_phylum) <- as.factor(".Phylum.Class.Order.Family.Genus") #paste the names(LDA_phylum) in excel
#write.table(LDA_phylum, file=paste0(dir_data_cleaning, "LDA_phylum.txt"), sep="\t", row.names=F, col.names=F, quote=FALSE)
library(readr)
LDA_phylum <- read_delim(paste0(dir_data_cleaning, "LDA_phylum.txt"), 
                         ".", escape_double = FALSE, col_types = cols(X1 = col_skip()), 
                         trim_ws = TRUE)
LDA_phylum_diet <- cbind(LDA_phylum , LDA_diet[,2:5])
colnames(LDA_phylum_diet) <- c(names(LDA_phylum)[1:5] , "LDA_res" , "Diet" , "LDA_res2" , "sig")
write.table(LDA_phylum_diet, file=paste0(dir_data_cleaning, "LDA_phylum_diet.txt"), sep="\t", row.names=F, col.names=T, quote=FALSE)

# Select your significativ value and taxa
LEFSE_sig <- subset(LDA_phylum_diet, LDA_phylum_diet$LDA_res2 >= 3)
LEFSE_sig_genus <- subset(LEFSE_sig, LEFSE_sig$Genus %in% as.character(na.exclude(LEFSE_sig$Genus)))
LEFSE_sig_genus_vec <- paste(LEFSE_sig_genus$Phylum, LEFSE_sig_genus$Class, LEFSE_sig_genus$Order, LEFSE_sig_genus$Family, LEFSE_sig_genus$Genus, sep = "|")

biomarkers <- paste(LEFSE_sig_genus$Order, LEFSE_sig_genus$Genus, sep = "|")
save(biomarkers, file = paste0(dir_data_cleaning, "biomarkers.RData"))

sey_samp <- sey_gut.genus@sam_data
write.table(sey_samp, file=paste0(dir_data_cleaning, "sey_samp.txt"), sep="\t", row.names=F, col.names=T, quote=FALSE)
levels(sample_data(sey_gut.genus)$diet3) <- c("Carnivorous", "Herbivorous","Herbivorous")

physeq_phylum <- sey_gut.genus %>%    
  transform_sample_counts(function(x) {x/sum(x)} ) %>% # Transform to rel. abundance
  psmelt() %>%  
  filter(Abundance > 0) %>% # Melt to long format
  arrange(Genus)

physeq_phylum$Abundance <- physeq_phylum$Abundance/nrow(sample_data(sey_gut.genus))

physeq_phylum$tax <- paste(physeq_phylum$Phylum, physeq_phylum$Class, physeq_phylum$Order, physeq_phylum$Family, physeq_phylum$Genus, sep = "|")
save(physeq_phylum, file= paste0(dir_data_cleaning, "physeq_phylum.RData"))
#write.table(physeq_phylum ,file = paste0(dir_data_cleaning, "physeq_phylum.txt"), sep="\t",quote = F)

Diet_Pol_sey <- physeq_phylum
Diet_Pol_sey$tax <-  paste(Diet_Pol_sey$Order, Diet_Pol_sey$Genus, sep = "|")
length(physeq_phylum$tax)
## [1] 945
df_sey <- Diet_Pol_sey[,c("diet3","tax3","tax","Abundance")]
colnames(df_sey) <- c("family","item","score","value")
save(df_sey, file = paste0(dir_data_cleaning, "df_sey.RData"))

Let’s organize our data to plot corresponding colours depending on the compartment.

dir_data_cleaning <- paste0(path, "/analyses/04_data_cleaning/Fish/Core/LDA/")
load(paste0(dir_data_cleaning, "biomarkers.RData"))
load(paste0(dir_data_cleaning, "df_sey.RData"))
library(plyr)
print_biomarkers <- levels(factor(df_sey[df_sey$score %in% biomarkers,]$score)) # All biomarkers present in the sey.diet_genus RData file
others <- levels(factor(df_sey[!df_sey$score %in% biomarkers,]$score)) # All taxa which are not biomarkers
df_sey[!df_sey$score %in% biomarkers,]$score <- "Z-Other" # Call them other (Z to figure at the end of the list)

# Some biomarkers are in common so Output the frequences.
freq_herb <- table(df_sey[df_sey$family == "Herbivorous",]$score)/length(df_sey[df_sey$family == "Herbivorous",]$score)*100 
freq_herb <- freq_herb[!names(freq_herb) == "Z-Other"]
freq_carn <- table(df_sey[df_sey$family == "Carnivorous",]$score)/length(df_sey[df_sey$family == "Carnivorous",]$score)*100 
freq_carn <- freq_carn[!names(freq_carn) == "Z-Other"]

# Keep the common biomarkers of the herbivorous and carnivorous and the respective frequencies in each compartment
biom_common <- names(freq_herb[which(names(freq_herb) %in% names(freq_carn))])
freq_herb_common <- as.data.frame(freq_herb[names(freq_herb) %in% biom_common])
freq_carn_common <- as.data.frame(freq_carn[names(freq_carn) %in% biom_common])
freq_common <- cbind(freq_herb_common, freq_carn_common$Freq)
colnames(freq_common) <- c("Biomarkers", "Freq_herb" ,"Freq_carn")
# Class the biomarkers in the compartment where the value is the higher
biom_herb_to_keep <- freq_common$Biomarkers[which(freq_common$Freq_herb > freq_common$Freq_carn, T)]
biom_carn_to_keep <- freq_common$Biomarkers[which(freq_common$Freq_carn > freq_common$Freq_herb, T)]
# See which are the biomarkers for the herbivorous and which are the biomarkers for the carnivorous
biom_herb <- levels(factor(df_sey[df_sey$family == "Herbivorous",]$score))
biom_herb <- biom_herb[!biom_herb == "Z-Other"]
biom_herb <- biom_herb[!biom_herb %in% biom_carn_to_keep]
biom_carn <- levels(factor(df_sey[df_sey$family == "Carnivorous",]$score))
biom_carn <- biom_carn[!biom_carn == "Z-Other"]
biom_carn <- biom_carn[!biom_carn %in% biom_herb_to_keep]

# Color choice
herb_colors <- c("yellow" , "darkkhaki", "darkolivegreen",
                  "darkolivegreen2","gold4","chartreuse",
                  "aquamarine","darkgreen", "darkcyan",
                  "darkseagreen", "gold3", "darkslategray")
                 
pie(rep(1, 12), col= herb_colors)

carn_colors <- c("darkred","darksalmon","darkorchid4",
                "blueviolet","darkblue",
                "blue3", "brown1","deeppink")

pie(rep(1, 8), col= carn_colors)

polar_col <- c(carn_colors , herb_colors , 'Z_Other'="black")
# Add a prefix H (for herbivorous) or C (for carnivorous) in their respectiv biomarkers. In this way, they will be listed following 
# their respectiv compartment and no their names (easier for the add of the color in the ggplot)
df_sey[df_sey$score %in% biom_herb,]$score <- paste("H",df_sey[df_sey$score %in% biom_herb,]$score, sep= "-")
df_sey[df_sey$score %in% biom_carn,]$score <- paste("C",df_sey[df_sey$score %in% biom_carn,]$score, sep= "-")
source(paste0(dir_refdb, "polarHistogram.R"))
p <- polarHistogram(df_sey , familyLabel=T, innerRadius = 0.2, spaceFamily =7, circleProportion = 0.85)
p + ggplot2::scale_fill_manual(values= polar_col) +
  theme(legend.text = element_text(family = "serif", size = 3)) +
  theme(legend.position= "none") # to hide the legend because of the size

LS0tCnRpdGxlOiAiSW5mbHVlbmNlIG9mIHRoZSBjb3JhbC1tYWNyb2FsZ2FsIHNoaWZ0IG9uIGNvbXBvc2l0aW9ucyBvZiBtaWNyb2JpYWwgY29tbXVuaXRpZXMgaW4gc2Vhd2VlZHMgYW5kIGVudGVyaWMgbWljcm9iaW9tZXMgb2YgcmVlZiBmaXNoIGluIFNleWNoZWxsZXMiCnN1YnRpdGxlIDogRGF0YSBwcm9jZXNzZXMgJiBhbmFseXNlcwphdXRob3I6IHwKICB8IE1hcmllLUNoYXJsb3R0ZSwgQ2hldXRpbl5hLDFeLCBKZWFuLUNocmlzdG9waGUsIEF1Z3VldF5hXiwgU2ViYXN0aWVuLCBWaWxsZWdlcl5hXiwgJiBKYW1lcywgUm9iaW5zb25eYl4uICAKICA8cD4gPC9wPiAKICA8Zm9udCBzaXplPSIyIj4gXmFeIFVNUiBNYXJiZWMsQ05SUyxJUkQsIElmcmVtZXIsIFVuaXZlcnNpdMOpIGRlIE1vbnRwZWxsaWVyLCBCYXRpbWVudCAyNCwgQ2FtcHVzIFRyaW9sZXQsIE1vbnRwZWxsaWVyLDM0MDkwIEZyYW5jZTwvZm9udD4gIAogIDxmb250IHNpemU9IjIiPiBeYl4gTGFuY2FzdGVyIFVuaXZlcnNpdHksIExhbmNhc3RlciwgVS5LIDwvZm9udD4gIAogIDxwPiA8L3A+IAogIDxmb250IHNpemU9IjMiPiBeMV5UbyB3aG9tIGNvcnJlc3BvbmRlbmNlIHNob3VsZCBiZSBhZGRyZXNzZWQuIEUtbWFpbDogbWNjaGV1dGluQHlhaG9vLmVzPC9mb250PiAgCmFic3RyYWN0OiAiV29ya2Zsb3cgdG8gZ2VuZXJhdGUgcGh5bG9zZXEgb2JqZWN0cywgYW5hbHl6ZSBkYXRhLCBhbmQgY3JlYXRlIGZpZ3VyZXMgZm9yIHRoZSBpbmZsdWVuY2Ugb2YgdGhlIGNvcmFsLW1hY3JvYWxnYWwgc2hpZnQgaW4gU2V5Y2hlbGxlcyBvbiBtaWNyb2Jpb21lcyBvZiBzZWF3ZWVkcyBhbmQgZ3V0IGlmIHJlZWYgZmlzaC4gSGVyZSB3ZSByZXBvcnQgYm90aCBtZXRob2RzIGFuZCByZXN1bHRzIGluIHBsYWluIHRleHQgYW5kIFIgY29kZS4gWW91IGNhbiBjaG9vc2UgdG8gc2hvdyBhbGwgY29kZSBvciBoaWRlIHRoZSBjb2RlIHVzaW5nIHRoZSBidXR0b24gaW4gdGhlIHVwcGVyIHJpZ2h0IGhhbmQgY29ybmVyIG9mIHRoZSBmcm9udCBwYWdlIChkZWZhdWx0IGlzIGhpZGUpIGFzIHdlbGwgYXMgZG93bmxvYWQgdGhlIC5SbWQgZmlsZSB0byB0d2VhayB0aGUgY29kZS4iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IAogICAga2VlcF9tZDogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogIHBkZl9kb2N1bWVudDogZGVmYXVsdAojY29vbF90aGVtZXM6IGRlZmF1bHQsIGNlcnVsZWFuLCBjb3NtbywgZGFya2x5LCBmbGF0bHksIGpvdXJuYWwsIGx1bWVuLCBzYW5kc3RvbmUsIHNpbXBsZXgsIHNwYWNlbGFiLCB1bml0ZWQsIHlldGkKLS0tCgpgYGB7ciBzZXR1cCwgZXZhbCA9IEZ9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gRkFMU0UpCnJlbW92ZShsaXN0ID0gbHMoKSkKY3Jhbl9wYWNrYWdlcyAgIDwtIGMoImtuaXRyIiwgInBoeWxvc2VxR3JhcGhUZXN0IiwgInBoeWxvc2VxIiwgInNoaW55IiwgIm1pY3JvYmlvbWUiLAogICAgICAgICAgICAgICAgICAgICAidGlkeXZlcnNlIiwgIm1pbmlVSSIsICJjYXJldCIsICJwbHMiLCAiZTEwNzEiLCAiZ2dwbG90MiIsIAogICAgICAgICAgICAgICAgICAgICAicmFuZG9tRm9yZXN0IiwiZW50cm9wYXJ0IiwgInZlZ2FuIiwgInBseXIiLCAiZHBseXIiLCAiaGVyZSIsCiAgICAgICAgICAgICAgICAgICAgICJnZ3JlcGVsIiwgIm5sbWUiLCAiUi51dGlscyIsICJncmlkRXh0cmEiLCJncmlkIiwgImdvb2dsZWRyaXZlIiwgCiAgICAgICAgICAgICAgICAgICAgICJnb29nbGVzaGVldHMiLCAicGhhbmdvcm4iLCAiZGV2dG9vbHMiLCAicm1hcmtkb3duIiwgInN5cyIsCiAgICAgICAgICAgICAgICAgICAgICJyZXNoYXBlMiIsICJkZXZ0b29scyIsICJQTUEiLCJzdHJ1Y3RTU0kiLCJhZGU0IiwgImFwZSIsCiAgICAgICAgICAgICAgICAgICAgICJCaW9zdHJpbmdzIiwgImlncmFwaCIsICJnZ25ldHdvcmsiLCAiaW50ZXJncmFwaCIsICJpcHMiLAogICAgICAgICAgICAgICAgICAgICAic2NhbGVzIiwgImthYmxlRXh0cmEiLCAicGdpcm1lc3MiLCAidHJlZW1hcCIsICJrbml0ciIsImthYmxlRXh0cmEiLAogICAgICAgICAgICAgICAgICAgICAicnN0dWRpb2FwaSIgLCJkYXRhLnRhYmxlIiwiRFQiLCJwYW5kZXIiLCJmb3JtYXRSIiwiZ3JEZXZpY2VzIiwic3ZnUGFuWm9vbSIsCiAgICAgICAgICAgICAgICAgICAgICJSQ3VybCIsInBsb3RseSIsInBhaXJ3aXNlQWRvbmlzIiwgInN0cmluZ3IiKQpnaXRodWJfcGFja2FnZXMgPC0gYygiamZ1a3V5YW1hL3BoeWxvc2VxR3JhcGhUZXN0IikKYmlvY19wYWNrYWdlcyAgIDwtIGMoInBoeWxvc2VxIiwgImdlbmVmaWx0ZXIiLCAiaW1wdXRlIiwgImRhZGEyIiwgIkRFQ0lQSEVSIikKIyBJbnN0YWxsIENSQU4gcGFja2FnZXMgKGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZCkKI1NvbWUgcGFja2FnZXMgd291bGQgYmUgbm90IGF2YWlsYmFsZSBmb3IgeW91ciBSIHZlcnNpb24KaW5zdCA8LSBjcmFuX3BhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkKaWYgKGFueSghIGluc3QpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcyhjcmFuX3BhY2thZ2VzWyFpbnN0XSwgcmVwb3MgPSAiaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikgfQojIAppbnN0IDwtIGdpdGh1Yl9wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpCmlmIChhbnkoISBpbnN0KSkgewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihnaXRodWJfcGFja2FnZXNbIWluc3RdKSB9CgojIExvYWQgbGlicmFyaWVzCnNhcHBseShjKGNyYW5fcGFja2FnZXMsIGJpb2NfcGFja2FnZXMpLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCnNlc3Npb25JbmZvKCkKc2V0LnNlZWQoMTAwMCkKYGBgCgpgYGB7ciBzZXRfd2QsIGVjaG89RkFMU0V9CmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gZ2V0d2QoKSkKcGF0aCA9IGdldHdkKCkKIyBUaGlzIHdpbGwgc2V0d2QgdG8gd2hlcmV2ZXIgdGhlIC5SbWQgZmlsZSBpcyBvcGVuZWQuCmRpcl9zYW1wbGVfc2VsZWN0aW9uIDwtIHBhc3RlMChwYXRoLCIvYW5hbHlzZXMvMDFfc2VsZWN0X3NhbXBsZXMvIikKZGlyX3NlcV9wcm9jZXNzaW5nICAgPC0gcGFzdGUwKHBhdGgsIi9hbmFseXNlcy8wMl9wcm9jZXNzX3NlcXVlbmNlcy8iKQpkaXJfdGF4YV9hc3NpZ24gICAgICA8LSBwYXN0ZTAocGF0aCwiL2FuYWx5c2VzLzAzX2Fzc2lnbl90YXhvbm9teS8iKQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nLyIpCmRpcl9wcmltZXJzICAgPC0gcGFzdGUwKHBhdGgsIi9kaXJfZGF0YV9zb3VyY2UvcHJpbWVyc19zZXF1ZW5jZXMvIikKZGlyX3JlZmRiICAgPC0gcGFzdGUwKHBhdGgsIi9kaXJfZGF0YV9zb3VyY2UvcmVmZXJlbmNlX2RhdGFiYXNlcy8iKQpkaXJfZmFzdHFfc291cmNlIDwtIHBhc3RlMChwYXRoLCIvZGlyX2RhdGFfc291cmNlL3NlcXVlbmNlcy8iKQpgYGAKCmBgYHtyIG1rZGlycywgZWNobz1GQUxTRSwgZXZhbD1GfQpkaXIuY3JlYXRlKGRpcl9zYW1wbGVfc2VsZWN0aW9uLCByZWN1cnNpdmUgPSBUUlVFKQpkaXIuY3JlYXRlKGRpcl9zZXFfcHJvY2Vzc2luZywgcmVjdXJzaXZlID0gVFJVRSkKZGlyLmNyZWF0ZShkaXJfdGF4YV9hc3NpZ24sIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoZGlyX3ByaW1lcnMsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpci5jcmVhdGUoZGlyX3JlZmRiLCByZWN1cnNpdmUgPSBUUlVFKQpkaXIuY3JlYXRlKGRpcl9mYXN0cV9zb3VyY2UgLHJlY3Vyc2l2ZSA9VCkgCmBgYAoKKioqCgojIyBQcmVhbWJsZQoKPHN0eWxlPgpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I0ZCREZCNDsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJibHVlIj4KPGZvbnQgc2l6ZT0iNCI+VGhpcyBkb2N1bWVudCBpcyAgKippbnRlcmFjdGl2ZSoqLiBZb3UgY2FuICoqc29ydCBhbmQgc2Nyb2xsKiogdGhyb3VnaCBtb3N0IG9mIHRoZSB0YWJsZXMgYW5kIHRoZSAqKnBoeWxvZ2VuZXRpYyB0cmVlIGlzIHpvb21hYmxlKiouIEluIHRoZSB1cHBlciByaWdodCBoYW5kIGNvcm5lciBvZiB0aGUgZnJvbnQgcGFnZSBpcyBhIGBDb2RlYCBidXR0b24uIFVzZSB0aGlzIHRvIHNob3cgb3IgaGlkZSBhbGwgdGhlIGNvZGUgaW4gdGhlIGRvY3VtZW50IChkZWZhdWx0IGlzIGhpZGUpIGFzIHdlbGwgYXMgZG93bmxvYWQgdGhlIGAuUm1kYCBmaWxlIHdoaWNoIHlvdSBjYW4gdXNlIHRvIGV4dHJhY3QgdGhlIGNvZGUuIERhdGEgcHJvZHVjdHMgZnJvbSB0aGUgZmluYWwgcGFwZXIgYXJlIGhpZ2hsaWdodGVkIGluIDxmb250IHNpemU9IjMiIGNvbG9yPSJyZWQiPlJlZDwvZm9udD4uPC9mb250Pgo8L2Rpdj4KCiMjIyBEZWZpbml0aW9ucyAmIEFiYnJldmlhdGlvbnMgIAoKKiBbQW1wbGljb24gU2VxdWVuY2UgVmFyaWFudF0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9pc21lajIwMTcxMTkpe3RhcmdldD0iX2JsYW5rIn0gKCoqQVNWKiopOiBFeGFjdCBzZXF1ZW5jZSB2YXJpYW50LS0tYW5hbG9nb3VzIHRvIGFuIE9UVS0tLWJ1dCB3aXRoIHNpbmdsZSBudWNsZW90aWRlIHJlc29sdXRpb24uICAKKiBbQ29yZSBtaWNyb2Jpb21lXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0ODE3NjcxLyl7dGFyZ2V0PSJfYmxhbmsifQooKipDb3JlKiopOiBBIGRpc3BlcnNpb24gaW5kZXggaXMgY2FsY3VsYXRlZCBmb3IgZWFjaCBBU1YgYXMgdGhlIHJhdGlvIG9mIHRoZSB2YXJpYW5jZSB0byB0aGUgbWVhbiBhYnVuZGFuY2UgbXVsdGlwbGllZCBieSB0aGUgb2NjdXJyZW5jZSA6CgogJCRJRF94ID0gXGZyYWN7VmFyaWFuY2VfeH17XHN1bV97QWJvbmRhbmNlX3h9fSQkCiAKd2hlcmUgJElEX3gkIGlzIHRoZSBpbmRleCBvZiBkaXNwZXJzaW9uIG9mIHRoZSAkQVNWX3gkLgpFYWNoIGNhbGN1bGF0ZWQgaW5kZXggd2FzIGNvbXBhcmVkIHRvIGEgUG9pc3NvbiBkaXN0cmlidXRpb24gKFtNYWd1cnJhbiAmIEhlbmRlcnNvbiwgMjAwM10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uYXR1cmUwMTU0NykpLCBhbmQgdGVzdGVkIHdoZXRoZXIgdGhleSB3ZXJlIGluY2x1ZGVkIGJldHdlZW4gdGhlIDIuNSUgYW5kIDk3LDUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgb2YgdGhlIEtoaV4yXiBkaXN0cmlidXRpb24gKEtyZWJzLCAxOTk5KS4gCgoqIFsqKklSICYgSFIqKl17dGFyZ2V0PSJfYmxhbmsifTogSW1wYWN0ZWQgUmVlZiBhbmQgSGVhbHRoeSBSZWVmIGNvbmRpdGlvbnMgd2hlcmUgKipJUnMqKiBhcmUgcmVlZnMgd2hpY2ggaGF2ZSB1bmRlcmdvbmUgYSBtYWNyb2FsZ2FlIGludmFzaW9uIHdoaWxlICoqSFJzKiogYXJlIHJlZWZzIHdpdGggYSBwcmUtYmxlYWNoaW5nIGRpc3R1cmJhbmNlIHN0YXRlLiAgIAoKIyMjIFN0dWR5IGdvYWxzCjEuIERlc2NyaWJlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZWQgZmlzaCBhbmQgZW52aXJvbm1lbnRhbCBwaWVjZXMgYmV0d2VlbiByZWVmIGNvbmRpdGlvbnMuCjIuIEFzc2VzcyB0aGUgdGF4b25vbWljIGNvbXBvc2l0aW9uIG9mIGludGVzdGluYWwgY29tbXVuaXRpZXMgZnJvbSByZWVmIGZpc2ggYW5kIGZyb20gYWxnYWUgKHR1cmYgYW5kICpTYXJnYXNzdW0qKS4gIAozLiBBbmFseXNlIHRoZSBwb3RlbnRpYWwgZWZmZWN0IG9mIHRoZSBjb3JhbC1tYWNyb2FsZ2FsIHNoaWZ0IG9uIHRoZWlyIG1pY3JvYmlhbCBjb21tdW5pdGllcy4gIAo0LiBJZGVudGlmeSB3aGljaCBkZXRlcm1pbmFudHMgYXJlIHRoZSBkcml2ZXJzIG9mIHRoZSBtaWNyb2JpYWwgY29tcG9zaXRpb24gb2YgdGhlIGVudGVyaWMgbWljcm9iaW9tZSBvZiB0aGUgcmVlZiBmaXNoLiAgCgoqKioKCjxhIGlkPSJiYWNrIHRvIHRvcCI+PC9hPiAKCiMjIFdvcmtmbG93IG92ZXJ2aWV3CgojIyMjIFtQYXJ0IEk6IERBREEyIHByb2Nlc3NdKCNQYXJ0IEk6IERBREEyIHByb2Nlc3MpCgpUaGUgb2J0YWluZWQgcmVhZHMgZnJvbSB0aGUgc2VxdWVuY2luZyBwbGF0Zm9ybSAoR2Vub3RvdWwsIFRvdWxvdXNlKSB3ZXJlIGRlbXVsdGlwbGV4ZWQgYW5kIGxpbmtlcnMgd2l0aCBwcmltZXJzIHNlcXVlbmNlcyB3ZXJlIHJlbW92ZWQgYmVmb3JlIGJlaW5nIHByb2Nlc3NlZCB0aHJvdWdoIFtEQURBMiBwaXBlbGluZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNDkyNzM3Ny8pe3RhcmdldD0iX2JsYW5rIn0gKENhbGxhaGFuIGV0IGFsLiwgMjAxNikuIEJyaWVmbHksIHNlcXVlbmNlcyB3ZXJlIHRyaW1tZWQgYW5kIGZpbHRlcmVkIGZvciBxdWFsaXR5LCBkZXJlcGxpY2F0ZWQgYW5kIGluZmVycmVkIGluIEFTVnMgKEdsYXNzbWFuICYgTWFydGlueSwgMjAxOCkuIEZvcndhcmQgYW5kIHJldmVyc2UgQVNWcyB3ZXJlIG1lcmdlZCBhbmQgZmluYWxseSBnZW5lcmF0ZWQgYSBjb3VudCB0YWJsZSB3aGVyZSBjaGltZXJhIHdlcmUgaWRlbnRpZmllZCBhbmQgcmVtb3ZlZC4gVGhlIHRheG9ub215IGFzc2lnbm1lbnQgd2FzIHBlcmZvcm1lZCB1c2luZyB0aGUgW1NJTFZBIHJlZmVyZW5jZSBkYXRhYmFzZSAoKnJlbGVhc2UgMTIzKildKGh0dHBzOi8vYWNhZGVtaWMub3VwLmNvbS9uYXIvYXJ0aWNsZS80MS9EMS9ENTkwLzEwNjkyNzcpe3RhcmdldD0iX2JsYW5rIn0gKFF1YXN0IGV0IGFsLiwgMjAxMykuIEEgW3BoeWxvc2VxXShodHRwczovL2pvdXJuYWxzLnBsb3Mub3JnL3Bsb3NvbmUvYXJ0aWNsZT9pZD0xMC4xMzcxL2pvdXJuYWwucG9uZS4wMDYxMjE3KXt0YXJnZXQ9Il9ibGFuayJ9IG9iamVjdCAoTWNNdXJkaWUgJiBIb2xtZXMsIDIwMTMpIHdhcyBnZW5lcmF0ZWQgZm9yIGZ1cnRoZXIgc3RhdGlzdGljYWwgYW5hbHlzaXMuIAoKIyMjIyBbUGFydCBJSTogUGh5bG9zZXEgcHJvY2Vzc10oI1BhcnQgSUk6IFBoeWxvc2VxIHByb2Nlc3MpCgpUbyBtaW5pbWl6ZSB0aGUgZWZmZWN0IG9mIGNvbnRhbWluYXRpb24gZHVyaW5nIHRoZSBkaXNzZWN0aW9uLCBleHRyYWN0aW9uIGFuZCBhbXBsaWZpY2F0aW9uIHN0ZXBzLCB0aGUgQVNWcyB0YXhvbm9taWNhbGx5IGFzc2lnbmVkIHRvIEV1a2FyeWEgS2luZ2RvbSAoPCAwLjElKSwgdGhlIG9yZ2FuZWxsZXMgcmVhZHMgKENobG9yb3BsYXN0IGFuZCBNaXRvY2hvbmRyaWEgKSBhbmQgdG8gNDAga2l0IGNvbnRhbWluYW50IGdlbnVzIGRlc2NyaWJlZCBpbiBbU2FsdGVyIGV0IGFsLiAoMjAxNCldKGh0dHBzOi8vYm1jYmlvbC5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMjkxNS0wMTQtMDA4Ny16KSB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgZGF0YWJhc2UuIEJlY2F1c2Ugb2YgdGhlIGhpZ2ggdmFyaWFiaWxpdHkgb2Ygc2VxdWVuY2luZyBkZXB0aCwgdGFibGVzIG9mIEFTVnMgd2VyZSBub3JtYWxpemVkIGJhc2VkIG9uIHRoZSBsb3dlc3QgbnVtYmVyIG9mIHNlcXVlbmNlcyBmb3IgZWFjaCBjb21wYXJ0bWVudCAoZ3V0LCBtYWNyb2FsZ2FlIGFuZCB0dXJmKS4gVGh1cywgdGhpcyBwYXJ0IGNyZWF0ZSBzZXZlcmFsIHBoeWxvc2VxIG9iamVjdCBpbiBvcmRlciB0byB1c2UgZm9yIHRoZSBhbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkuCgojIyMjIFtQYXJ0IElJSTogRmlzaCBDb21tdW5pdHkgQ29tcG9zaXRpb24gYmV0d2VlbiBSZWVmc10oI1BhcnQgSUlJOiBGaXNoIENvbW11bml0eSBDb21wb3NpdGlvbiBiZXR3ZWVuIFJlZWZzKSAKCkJlZm9yZSBhbmFseXppbmcgdGhlIG1pY3JvYmlhbCBjb21wb3NpdGlvbnMsIHdlIGFzc2VzcyB0aGUgaG9zdCBkaXN0cmlidXRpb24gYmV0d2VlbiByZWVmcy4gVGhlIG1hY3JvYWxnYSBzaGlmdCBoYXMgYWxyZWFkeSBiZWVuIHN0dWR5IHRvIGFsdGVyIGZpc2ggY29tbXVuaXRpZXMgYW5kIHRyb3BoaWMgc3RydWN0dXJlIChbQnVya2VwaWxlICYgSGF5LCAoMjAwOCldKGh0dHBzOi8vd3d3LnBuYXMub3JnL2NvbnRlbnQvMTA1LzQyLzE2MjAxKSA7IFtOeXN0csO2bSBldCBhbC4sICgyMDA4KV0oaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9hcnRpY2xlLzEwLjEwMDclMkZzMDAzMzgtMDA4LTA0MjYteikpLiBXZSBmaXJzdCBhbmFseXplIG91ciBzYW1wbGluZyByZXN1bHRzIGluIG9yZGVyIHRvIHVuZGVycGlubmVkIHRoZSBwcmV2aW91cyBvYnNlcnZhdGlvbnMgYW5kIHRvIHVuZGVyc3RhbmQgaG93IG1pY3JvYmlvbWUgaXMgYWRhcHRlZCB0byB0aGUgaGVhbHRoIHJlZWYgc3RhdHVzLgoKIyMjIyBbUGFydCBJVjogRGV0ZXJtaW5hdGlvbiBhbmQgZGVzY3JpcHRpb24gb2YgdGhlIGVudGVyaWMgYW5kIGFsZ2FsIGNvcmUgbWljcm9iaW9tZXNdKCNQYXJ0IElWOiBEZXRlcm1pbmF0aW9uIGFuZCBkZXNjcmlwdGlvbiBvZiB0aGUgZW50ZXJpYyBhbmQgYWxnYWwgY29yZSBtaWNyb2Jpb21lcykKCldlIGZpcnN0IGRlc2NyaWJlIHRoZSBjb3JlIG1pY3JvYmlvbWUgYXMgbWljcm9iaW9tZSBjb25zdGl0dXRlZCBieSB0aGVvcml0aWNhbCBwZXJtYW5lbnQgQVNWcy4gSSBhIGZpcnN0IHN0ZXAsIGVudGVyaWMgYW5kIG1hY3JvLWFsZ2FsIGNvcmUgYmFjdGVyaW9tZXMgd2VyZSBpbmRlcGVuZGVudGx5IGlkZW50aWZpZWQgYnkgZXhhbWluaW5nIHRoZSBzcGVjaWVzIGFidW5kYW5jZSBkaXN0cmlidXRpb24gKFNBRCkgcGF0dGVybnMgb2YgZWFjaCBBU1YgYW5kIGJ5IHBhcnRpdGlvbmluZyB0aGUgU0FEIGludG8gY29yZSBhbmQgc2F0ZWxsaXRlIEFTVnMgKFtNYWd1cnJhbiAmIEhlbmRlcnNvbiwgMjAwM10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uYXR1cmUwMTU0NykpLiBGb3IgdGhpcyBwdXJwb3NlLCB0aGUgaW5kZXggb2YgZGlzcGVyc2lvbiBmb3IgZWFjaCBBU1Ygd2FzIGNhbGN1bGF0ZWQgYXMgdGhlIHJhdGlvIG9mIHRoZSB2YXJpYW5jZSB0byB0aGUgbWVhbiBhYnVuZGFuY2UgKFZNUikgbXVsdGlwbGllZCBieSB0aGUgb2NjdXJyZW5jZS4gCiQkSURfeCA9IFxmcmFje1ZhcmlhbmNlX3h9e1xzdW1fe0Fib25kYW5jZV94fX0kJAogCndoZXJlICRJRF94JCBpcyB0aGUgaW5kZXggb2YgZGlzcGVyc2lvbiBvZiB0aGUgJEFTVl94JC4KVGhpcyBpbmRleCB3YXMgdXNlZCB0byBtb2RlbCB3aGV0aGVyIGxpbmVhZ2VzIGZvbGxvdyBhIFBvaXNzb24gZGlzdHJpYnV0aW9uIChpLmUuLCBzdG9jaGFzdGljIGRpc3RyaWJ1dGlvbiksIGZhbGxpbmcgYmV0d2VlbiB0aGUgMi41IGFuZCA5Ny41JSBjb25maWRlbmNlIGludGVydmFsIG9mIHRoZSDPhzIgZGlzdHJpYnV0aW9uIChLcmVicywgMTk5OSkuIApDb25jZXJuaW5nIHRoZSBhbHBoYSBkaXZlcnNpdHksIHRhYmxlcyB3ZXJlIG5vcm1hbGl6ZWQgd2l0aCB0aGUgYWJ1bmRhbmNlIG9mIHRoZSBtaW5pbWFsIHNhbXBsaW5nIHNpemUuIFJpY2huZXNzIG9ic2VydmVkIGFuZCBTaGFubm9uIGluZGV4IHdlcmUgY2FsY3VsYXRlZCBhbmQgY29tcGFyZWQgYmV0d2VlbiBib3RoIGNvbXBhcnRtZW50LiBUaGVuLCB0aGUgYmV0YSBkaXZlcnNpdHkgd2FzIGNhbGN1bGF0ZWQgd2l0aCB0aGUgbm9ybWFsaXplZCB0YWJsZXMgZm9yIGJvdGggY29yZXMuIEEgYmxhc3Qgb24gdGhlIGRpZmZlcmVudCBBU1ZzIHdhcyBhbHNvIG1hZGUgYW5kIHBsb3RlZCB0aHJvdWdoIEl0b2wgaW4gb3JkZXIgdG8gZGV0ZXJtaW5lIHRoZSBvcmlnaW4gb2YgdGhlIEFTVnMgaW4gdGhlIGVudGVyaWMgYW5kIGFsZ2FsIGNvcmVzLiBBbHNvLCB0byBkZXRlY3QgdGhlIHRheGEgZGVzY3JpcHRvciBvZiBlYWNoIGNvbXBhcnRtZW50LCB3ZSBwcm9jZWVkZWQgdG8gYSBMaW5lYXIgRGlzY3JpbWluYW50IGFuYWx5c2VzIG9uIExlZlNlIHRvIGRldGVjdCB3aGljaCBBU1ZzIGFyZSBiaW9tYXJrZXJzIG9mIGVhY2ggY29tcGFydG1lbnRzIChbU2VnYXRhIGV0IGFsLiwgMjAxMV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMjE3MDI4OTgpKS4KCiMjIyMgW1BhcnQgVjogSW5mbHVlbmNlIG9mIHRoZSBjb3JhbC1tYWNyb2xhZ2FsIHNoaWZ0IG9uIG1pY3JvYmlhbCBjb21wb3NpdGlvbnNdKCNQYXJ0IFY6IEluZmx1ZW5jZSBvZiB0aGUgY29yYWwtbWFjcm9sYWdhbCBzaGlmdCBvbiBtaWNyb2JpYWwgY29tcG9zaXRpb25zKSAKCkluIHRoaXMgcGFydCwgd2UgdHJlYXRlZCB0aGUgbWFpbiBpc3N1ZSBjb21wYXJpbmcgdGhlIGVudmlyb25tZW50YWwgc2FtcGxlcyBhbmQgZW50ZXJpYyBjb3JlIG1pY3JvYmlvbWVzIGZyb20gSFJzIGFuZCBJUnMgd2l0aCBhbHBoYSBkaXZlcnNpdHkgYW5kIGJldGEgZGl2ZXJzaXR5IHdpdGggUEVSTUFOT1ZBLgpDb25jZXJuaW5nIHRoZSBlbnRlcmljIG1pY3JvYmlvbWUsIG91ciBzYW1wbGluZyBzaXplIHBlcm1pdGVkIHRvIHRlc3QgZm91ciBzcGVjaWVzICgqQXByaW9uIHZpcmVzY2VucyosICpTY2FydXMgZ2hvYmJhbiosICpMZXRocmludXMgbWFoc2VuYSogYW5kICpMZXRocmludXMgZW5pZ21hdGljdXMqKSwgdHdvIGdlbnVzICgqTGV0aHJpbnVzKiBzcC4sICpTY2FydXMqIHNwLikgYW5kIG9uZSBmYW1pbHkgKEx1dGphbmlkYWUpLgoKIyMjIyBbUGFydCBWSTogT3RoZXIgZHJpdmVycyBvZiBlbnRlcmljIG1pY3JvYmlhbCBjb21tdW5pdGllc10oI1BhcnQgVkk6IE90aGVyIGRyaXZlcnMgb2YgZW50ZXJpYyBtaWNyb2JpYWwgY29tbXVuaXRpZXMpCgpGaW5hbGx5LCBpbiBvcmRlciB0byBkZXRlcm1pbmUgd2hpY2ggZGV0ZXJtaW5hbnRzIGFyZSB0aGUgZHJpdmVycyBvZiB0aGUgbWljcm9iaWFsIGNvbXBvc2l0aW9uIG9mIHRoZSBlbnRlcmljIG1pY3JvYmlvbWUgb2YgdGhlIHJlZWYgZmlzaCwgd2UgdGVzdGVkIHRoZSBlZmZlY3Qgb2YgdGhlIHBoeWxvZ2VueSBhbmQgdGhlIGRpZXQgYnkgY29tcGFyaW5nIHRoZSBoZXJiaXZvcmUgYW5kIHRoZSBpbnZlcnRpdm9yZXMuIEFzIGZvciB0aGUgWyoqUGFydCBJVioqXSgjUGFydCBJVjogQ29tcG9zaXRpb25zIG9mIHRoZSBtaWNyb2Jpb21lcyBvZiAqU2FyZ2Fzc3VtKiwgdHVyZiBhbmQgY29yZSBndXQpLCB3ZSBnZW5lcmF0ZWQgYSBMREEgaW4gb3JkZXIgdG8gZGV0ZWN0IHRoZSBtaWNyb2JpYWwgdGF4YSBiaW9tYXJrZXJzIGZvciBlYWNoIGRpZXQuCgo+IFBzOiBBbGwgdGFibGVzIGFuZCBmaWd1cmVzIHByZXNlbnRlZCBiZWxvdyB3ZXJlIHBvc3NpYmx5IG1vZGlmeSBiZWZvcmUgdG8gYmUgaW5zZXJ0IGluIHRoZSBwdWJsaWNhdGlvbi4gV2UgYWxzbyBpbmNsdWRlIG1hbnkgYWRkaXRpb25hbCBkYXRhIHByb2R1Y3RlcyB0aGF0IHdlcmUgbm90IHBhcnQgb2YgdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uLiAgCgoqKioKCjxhIGlkPSJQYXJ0IEk6IERBREEyIHByb2Nlc3MiPjwvYT4gIAoKIyMgUGFydCBJOiBEQURBMiBwcm9jZXNzCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKIyMjIyBQcmVwYXJhdGlvbiBvZiB5b3VyIHNlcXVlbmNlCkZpcnN0LCB5b3UgbmVlZCB0byBsb2FkIHRoZSBvcmlnaW5hbCBSMSBSMiByZWFkcyBpbiB0aGUgKiovZGlyX2Zhc3RxX3NvdXJjZSoqIGZvbGRlci4gVGhlbiwgZG93bmxvYWQgdGhlIFtTSUxWQSBkYXRhYmFzZSByZWZlcmVuY2VzXShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzExNzI3ODMjLlhwU0IyNU16WlFJKSBpbnRvIHRoZSAqKi9kaXJfcmVmX2RiKiogZm9sZGVyLiBDb25jZXJuaW5nIHRoZSBwcmltZXJzICoqNTE1Ri1ZKiogJiAqKjkyNlIqKiB1c2VkIGZvciB0aGlzIHB1YmxpY2F0aW9uLCB0aGVpciBzZXF1ZW5jZXMgYXJlIHdyaXR0ZW4gcmlnaHQgaGVyZS4gWW91IGNhbiBhbHNvIHdyaXRlIGEgLnR4dCBmaWxlcyBmb3IgZWFjaCBwcmltZXIgeW91IHVzZWQgYW5kIGxvYWQgaXQgaW4gdGhlICoqL2Rpcl9wcmltZXJzKiogZm9sZGVyIHRvIGNhbGwgdGhlbSB3aGVuIHlvdSBuZWVkIGl0LgoKYGBge3IgcHJpbWVycyBkZXNjcmlwdGlvbn0KcHJpbWVyXzUxNUZZIDwtICJHVEdZQ0FHQ01HQ0NHQ0dHVEFBIgpwcmltZXJfOTI2UiA8LSAiQ0NHWUNBQVRUWU1UVFRSQUdUVFQiCmBgYAoKV2UgbmVlZCB0byByZWFkIHRoZSBmb2xkZXJzIHdoaWNoIGNvbnRhaW4gb3VyIHNlcXVlbmNlcyxwcmltZXJzIHNlcXVlbmNlcywgZW52aXJvbm1lbnRhbCBkYXRhc2V0IGFuZCByZWZlcmVuY2VzLgpgYGB7ciByZWZfZm9sZGVyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KHN0cmluZ3IpCm5tc19zZXFfcnVucyAgPC0gbGlzdC5maWxlcyhkaXJfZmFzdHFfc291cmNlKQpwYXRoc19zZXFfcnVucyA8LSBsaXN0LmZpbGVzKGRpcl9mYXN0cV9zb3VyY2UsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgc2V0TmFtZXMobm1zX3NlcV9ydW5zKQoKbm1zX3JlZmRiICAgPC0gbGlzdC5maWxlcyhkaXJfcmVmZGIpCnBhdGhzX3JlZmRiIDwtIGxpc3QuZmlsZXMoZGlyX3JlZmRiLCBmdWxsLm5hbWVzID0gVFJVRSkgJT4lIHNldE5hbWVzKG5tc19yZWZkYikKCm5tc19wcmltZXJzICAgPC0gbGlzdC5maWxlcyhkaXJfcHJpbWVycykKcGF0aHNfcHJpbWVycyA8LSBsaXN0LmZpbGVzKGRpcl9wcmltZXJzLCBmdWxsLm5hbWVzID0gVFJVRSkgJT4lIHNldE5hbWVzKG5tc19wcmltZXJzKQpgYGAKCllvdSBoYXZlIFIxIGFuZCBSMiByZWFkcyB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIHNlcXVlbmNpbmcgbmFtZXMgd2hpY2ggY2FuIGJlIHZlcnkgdWdseS4KRmlyc3QsIGdldCB0aGUgbGlzdCBvZiB5b3VyIHNhbXBsZXMgYW5kIGV4Y3RyYWN0IHRoZSBzYW1wbGUgbmFtZXM6IApgYGB7ciBzYW1wbGVzX2xpc3QgYW5kIG5hbWVzICwgZXZhbD1GfQpmbnMgPC0gc29ydChsaXN0LmZpbGVzKGRpcl9zYW1wbGVfc2VsZWN0aW9uLCBmdWxsLm5hbWVzID0gVFJVRSkpCmZucyA8LSBmbnNbc3RyX2RldGVjdChiYXNlbmFtZShmbnMpLCAiLmZhc3RxIildCmZuc19SMSA8LSBmbnNbc3RyX2RldGVjdChiYXNlbmFtZShmbnMpLCAiUjEiKV0KZm5zX1IyIDwtIGZuc1tzdHJfZGV0ZWN0KGJhc2VuYW1lKGZucyksICJSMiIpXQppZihsZW5ndGgoZm5zX1IxKSAhPSBsZW5ndGgoZm5zX1IyKSkgc3RvcCgiRm9yd2FyZCBhbmQgcmV2ZXJzZSBmaWxlcyBkbyBub3QgbWF0Y2guIikKCnNhbXBsZV9uYW1lcyA8LSBzYXBwbHkoc3Ryc3BsaXQoYmFzZW5hbWUoZm5zX1IxKSwgIl8iKSwgYFtgLCAxKQpzYW1wbGVfbmFtZXMKYGBgCgpPbmNlIHNhbXBsZSBuYW1lcyBjdXQsIHlvdSBjYW4gcmVtb3ZlIHRoZSBwcmltZXIgc2VxdWVuY2UgZnJvbSB5b3VyIGRhdGEgYnkgImNvdW50aW5nIiB0aGUgbnVtYmVyIG9mIG51Y2xlb3RpZGVzIG9mIGVhY2ggcHJpbWVyLiBCZWNhdXNlIG51Y2xlb3RpZGVzIG1heWJlIG1lIGZsb3dpbmcsIGl0IG5vdCBhZHZpc2VkIHRvIHJlbW92ZSB0aGUgc2VxdWVuY2Ugb2YgdGhlIHByaW1lciBieSBpdHMgbnVjbGVvdGlkZSBjb21wb3NpdGlvbi4KYGBge3IgcmVtb3ZlX3ByaW1lcl9zZXEgLCBldmFsID0gRn0KbGlicmFyeShyZWFkcikKcHJpbWVyX3NldF9md2QgPC0gcmVhZF9saW5lcyhwYXN0ZTAoZGlyX3ByaW1lcnMsICJwcmltZXJfIiwgIjUxNUYtWSIgLCAiLnR4dCIpKQpwcmltZXJfc2V0X3JldiA8LSByZWFkX2xpbmVzKHBhc3RlMChkaXJfcHJpbWVycywgInByaW1lcl8iLCAiOTI2UiIsICIudHh0IikpCnByaW1lcl9sZW5ndGhfZndkIDwtIHN0cl9sZW5ndGgocHJpbWVyX3NldF9md2RbMl0pCnByaW1lcl9sZW5ndGhfcmV2IDwtIHN0cl9sZW5ndGgocHJpbWVyX3NldF9yZXZbMV0pCgojIFlvdSBjYW4gYWxzbyB1c2UgdGhlIHNlcXVlbmNlIG9mIHRoZSB7ciBwcmltZXJzIGRlc2NyaXB0aW9ufQpgYGAKCiMjIyMgUXVhbGl0eSBwcm9maWxlcyBhbmQgZmlsdGVyL3RyaW0gdGhlIHNlcXVlbmNlcwpOb3cgeW91IGNhbiBwbG90IHRoZSBxdWFsaXR5IHByb2ZpbGVzIG9mIHlvdXIgcmVhZHMgKHdoaWNoIGlzIHVzZWx5IGJldHRlciBvbiB0aGUgUjEpIGluIG9yZGVyIHRvIHRydW5jYXRlIHRoZSBzZXF1ZW5jZXMgYmVmb3JlIHF1YWxpdHkgZHJhc3RpY2FsbHkgZGVjcmVhc2UuIFRoZW4sIHlvdSBjYW4gZmlsdGVyIHlvdXIgc2VxdWVuY2VzIGFuZCB0cmltIHRoZSBwcmltZXIgbGVuZ3RoLiAKCmBgYHtyIFF1YWxpdHkgcHJvZmlsZXMgYW5kIGZpbHRlcmluZyAsIGV2YWwgPSBGfQpkaXJfcXVhbGl0eV9wbG90cyA8LSBwYXN0ZTAoZGlyX3NlcV9wcm9jZXNzaW5nLCAiL3F1YWxpdHlfcGRmL3Bsb3RzLyIpCmRpcl9jcmVhdGUoZGlyX3F1YWxpdHlfcGxvdHMgLCByZWN1cnNpdmUgPSBUKQpxdWFsX1IxIDwtIHBsb3RRdWFsaXR5UHJvZmlsZShmbnNfUjFbMV0pCnF1YWxfUjIgPC0gcGxvdFF1YWxpdHlQcm9maWxlKGZuc19SMlsxXSkKCmdnc2F2ZShxdWFsX1IxLCBmaWxlID0gcGFzdGUwKGRpcl9xdWFsaXR5X3Bsb3RzICwgInF1YWxpdHlfcHJvZmlsZV9SMS5wbmciKSkKZ2dzYXZlKHF1YWxfUjIsIGZpbGUgPSBwYXN0ZTAoZGlyX3F1YWxpdHlfcGxvdHMsICJxdWFsaXR5X3Byb2ZpbGVfUjIucG5nIikpCgpmaWx0X1IxIDwtIHN0cl9jKGRpcl9maWx0ZXJlZCwgc2FtcGxlX25hbWVzLCAiX1IxX2ZpbHQuZmFzdHEiKQpmaWx0X1IyIDwtIHN0cl9jKGRpcl9maWx0ZXJlZCwgc2FtcGxlX25hbWVzLCAiX1IyX2ZpbHQuZmFzdHEiKQpuYW1lcyhmaWx0X1IxKSA8LSBzYW1wbGVfbmFtZXMKbmFtZXMoZmlsdF9SMikgPC0gc2FtcGxlX25hbWVzCnNldC5zZWVkKDEwMDApCgpvdXQgPC0gZmlsdGVyQW5kVHJpbShmbnNfUjEsIGZpbHRfUjEsIGZuc19SMiwgZmlsdF9SMiwgdHJ1bmNMZW49YygyNDAsMjQwKSwKICAgICAgICAgICAgICAgICAgICAgbWF4Tj0wLCBtYXhFRT1jKDIsMiksIHRydW5jUT0yLCB0cmltTGVmdD1jKHByaW1lcl9sZW5ndGhfZndkLHByaW1lcl9sZW5ndGhfcmV2KSAsIHJtLnBoaXg9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgY29tcHJlc3M9VFJVRSwgbXVsdGl0aHJlYWQ9VFJVRSkKaGVhZChvdXQpCgpzYW1wbGVfbmFtZXMgPC0gc2FwcGx5KHN0cnNwbGl0KGJhc2VuYW1lKGZpbHRfUjEpLCAiXyIpLCBgW2AsIDEpICMgQXNzdW1lcyBmaWxlbmFtZSA9IHNhbXBsZW5hbWVfWFhYLmZhc3RxLmd6CnNhbXBsZV9uYW1lc1IgPC0gc2FwcGx5KHN0cnNwbGl0KGJhc2VuYW1lKGZpbHRfUjIpLCAiXyIpLCBgW2AsIDEpICMgQXNzdW1lcyBmaWxlbmFtZSA9IHNhbXBsZW5hbWVfWFhYLmZhc3RxLmd6CmlmKCFpZGVudGljYWwoc2FtcGxlX25hbWVzLCBzYW1wbGVfbmFtZXNSKSkgc3RvcCgiRm9yd2FyZCBhbmQgcmV2ZXJzZSBmaWxlcyBkbyBub3QgbWF0Y2guIikKbmFtZXMoZmlsdF9SMSkgPC0gc2FtcGxlX25hbWVzCm5hbWVzKGZpbHRfUjIpIDwtIHNhbXBsZV9uYW1lcwpzZXQuc2VlZCgxMDAwKQpgYGAKCkZpbmFsbHksIHlvdSBjYW4gbGVhcm4gdGhlIGVycm9yIHJhdGVzIGZvciBib3RoIHJlYWRzIGFuZCBzYXZlIHRoZW0uIApgYGB7ciBMZWFybiB0aGUgZXJyb3IgcmF0ZSwgIGV2YWwgPSBGfQplcnJGIDwtIGxlYXJuRXJyb3JzKGZpbHRfUjEsbmJhc2VzPTFlOCwgbXVsdGl0aHJlYWQ9VFJVRSkKZXJyUiA8LSBsZWFybkVycm9ycyhmaWx0X1IyLCBuYmFzZXM9MWU4LCBtdWx0aXRocmVhZD1UUlVFKQpwbG90RXJyb3JzX0YgPC0gcGxvdEVycm9ycyhlcnJGLCBub21pbmFsUT1UUlVFKQpwbG90RXJyb3JzX1IgPC0gcGxvdEVycm9ycyhlcnJSLCBub21pbmFsUT1UUlVFKQpnZ3NhdmUocGxvdEVycm9yc19GLCBmaWxlID0gcGFzdGUwKGRpcl9xdWFsaXR5X3Bsb3RzICwgInBsb3RFcnJvcnNfRi5wbmciKSkKZ2dzYXZlKHBsb3RFcnJvcnNfUiwgZmlsZSA9IHBhc3RlMChkaXJfcXVhbGl0eV9wbG90cywgInBsb3RFcnJvcnNfUi5wbmciKSkKYGBgCgo+IFBzOiAgSWYgeW91IGhhdmUgYmlnIGRhdGEsIHBsZWFzZSBwcm9jZWVkIGRpcmVjdGx5IGF0IHRoZSBbUGFydCBJYjogREFEQTIgcHJvY2VzcyBmb3IgQklHIERBVEFdKCMgUGFydCBJYjogREFEQTIgcHJvY2VzcyBmb3IgQklHIERBVEEpLgoKIyMjIyBEZXJlcGxpY2F0aW9uIGFuZCBtZXJnaW5nIHNlcXVlbmNlcwpOb3csIHdlIGRlcmVwbGljYXRlIHRoZSBmaWx0ZXJlZCByZWFkcyBpbiBvcmRlciB0byBpbmZlciB0aGVtIGluIGRhZGEgZmlsZSB0byBtZXJnZS4KCmBgYHtyIERlcmVwbGljYXRpb24gJiBJbmZlcmVuY2UgLCBldmFsID0gRn0KI0RlcmVwbGljYXRpb24gc3RlcApkZXJlcEZzIDwtIGRlcmVwRmFzdHEoZmlsdF9SMSwgdmVyYm9zZT1UUlVFKQpkZXJlcFJzIDwtIGRlcmVwRmFzdHEoZmlsdF9SMiwgdmVyYm9zZT1UUlVFKQpuYW1lcyhkZXJlcEZzKSA8LSBzYW1wbGVfbmFtZXMKbmFtZXMoZGVyZXBScykgPC0gc2FtcGxlX25hbWVzCiMgSW5mZXJlbmNlIHN0ZXAKZGFkYUZzIDwtIGRhZGEoZGVyZXBGcywgZXJyPWVyckYsIG11bHRpdGhyZWFkPVRSVUUsIHBvb2wgPSBUKQpkYWRhUnMgPC0gZGFkYShkZXJlcFJzLCBlcnI9ZXJyUiwgbXVsdGl0aHJlYWQ9VFJVRSwgcG9vbCA9IFQpCmRhZGFGc1tbMV1dCmRhZGFSc1tbMV1dCiMgTWVyZ2luZyBzdGVwCm1lcmdlcnMgPC0gbWVyZ2VQYWlycyhkYWRhRnMsIGRlcmVwRnMsIGRhZGFScywgZGVyZXBScywgdmVyYm9zZT1UUlVFKQpoZWFkKG1lcmdlcnNbWzFdXSkKYGBgCgpOb3csIHdlIGNhbiBjb25zdHJ1Y3Qgb3VyIHNlcXVlbmNlIHRhYmxlICJzZXF0YWIiIGFuZCByZW1vdmUgY2hpbWVyYXMuIEl0IGlzIHJlY29tbWFuZGFibGUgdG8gdHJhY2sgdGhlIHJlYWRzIHRocm91Z2ggdGhlIHBpcGVsaW5lIHByb2Nlc3MKYGBge3IgY29uc3RydWN0IHNlcXVlbmNlIHRhYmxlICYgY2hpbWVyYXMgcmVtb3ZpbmcsIGV2YWwgPSBGfQpzZXF0YWIgPC0gbWFrZVNlcXVlbmNlVGFibGUobWVyZ2VycykKcm93Lm5hbWVzKHNlcXRhYikgPSBzYW1wbGVfbmFtZXMKZGltKHNlcXRhYikKdGFibGUobmNoYXIoZ2V0U2VxdWVuY2VzKHNlcXRhYikpKQoKc2VxdGFiLm5vY2hpbSA8LSByZW1vdmVCaW1lcmFEZW5vdm8oc2VxdGFiLCBtZXRob2Q9ImNvbnNlbnN1cyIsIG11bHRpdGhyZWFkPVRSVUUsIHZlcmJvc2U9VFJVRSkKZGltKHNlcXRhYi5ub2NoaW0pCnN1bShzZXF0YWIubm9jaGltKS9zdW0oc2VxdGFiKQpzYXZlUkRTKHNlcXRhYi5ub2NoaW0sIHBhc3RlMChkaXJfc2VxX3Byb2Nlc3NpbmcsInNlcXRhYi5ub2NoaW0ucmRzIikpCgojIF9fX18gVHJhY2sgcmVhZHMgdGhyb3VnaCB0aGUgcGlwZWxpbmUgLS0tLQpnZXROIDwtIGZ1bmN0aW9uKHgpIHN1bShnZXRVbmlxdWVzKHgpKQp0cmFjayA8LSBjYmluZChvdXQsIHNhcHBseShkYWRhRnMsIGdldE4pLCBzYXBwbHkobWVyZ2VycywgZ2V0TiksIHJvd1N1bXMoc2VxdGFiKSwgcm93U3VtcyhzZXF0YWIubm9jaGltKSkKY29sbmFtZXModHJhY2spIDwtIGMoImlucHV0IiwgImZpbHRlcmVkIiwgImRlbm9pc2VkIiwgIm1lcmdlZCIsICJ0YWJsZWQiLCAibm9uY2hpbSIpCnJvd25hbWVzKHRyYWNrKSA8LSBzYW1wbGVfbmFtZXMKaGVhZCh0cmFjaykKc2F2ZSh0cmFjaywgZmlsZSA9ICJ0cmFja181MTVGLVlfOTI2Ui5SRGF0YSIpCmBgYAoKKioqIAojIyMgUGFydCBJYjogREFEQTIgcHJvY2VzcyBmb3IgQklHIERBVEEKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpUaGVzZSBjaHVua3MgYXJlIGhpZ2hseSByZWNvbW1lbmRhYmxlIGlmIHlvdSBoYXZlIGEgaHVnZSBtb3VudCBvZiBzZXF1ZW5jZXMgIQoKYGBge3IgRGVyZXAgJiBJbmZlcmVuY2UgLCBldmFsID0gRn0KbWVyZ2VycyA8LSB2ZWN0b3IoImxpc3QiLCBsZW5ndGgoc2FtcGxlX25hbWVzKSkKbmFtZXMobWVyZ2VycykgPC0gc2FtcGxlX25hbWVzCmZvcihzYW0gaW4gc2FtcGxlX25hbWVzKSB7CiAgY2F0KCJQcm9jZXNzaW5nOiIsIHNhbSwgIlxuIikKICBkZXJlcEZzIDwtIGRlcmVwRmFzdHEoZmlsdF9SMVtbc2FtXV0pCiAgZGRGIDwtIGRhZGEoZGVyZXBGcywgZXJyPWVyckYsIG11bHRpdGhyZWFkPVRSVUUpCiAgZGVyZXBScyA8LSBkZXJlcEZhc3RxKGZpbHRfUjJbW3NhbV1dKQogIGRkUiA8LSBkYWRhKGRlcmVwUnMsIGVycj1lcnJSLCBtdWx0aXRocmVhZD1UUlVFKQogIG1lcmdlciA8LSBtZXJnZVBhaXJzKGRkRiwgZGVyZXBGcywgZGRSLCBkZXJlcFJzKQogIG1lcmdlcnNbW3NhbV1dIDwtIG1lcmdlcgp9CnJtKGRlcmVwRnMpOyBybShkZXJlcFJzKQpgYGAKTm93IHRoZSBjb25zdHJ1Y3Rpb24gb2YgdGhlIHNlcXVlbmNlIHRhYmxlIApgYGB7ciBjb25zdHJ1Y3Qgc2VxdWVuY2UgdGFibGUgYW5kIGNoaW1lcmFzIHJlbW92aW5nLCBldmFsID0gRn0Kc2VxdGFiIDwtIG1ha2VTZXF1ZW5jZVRhYmxlKG1lcmdlcnMpCnJvdy5uYW1lcyhzZXF0YWIpID0gc2FtcGxlX25hbWVzCmRpbShzZXF0YWIpCnRhYmxlKG5jaGFyKGdldFNlcXVlbmNlcyhzZXF0YWIpKSkKCnNhdmVSRFMoc2VxdGFiLCBwYXN0ZTAoZGlyX3NlcV9wcm9jZXNzaW5nLCJzZXF0YWIucmRzIikpCgojIElmIHByb2Nlc3NpbmcgYSBzaW5nbGUgc2FtcGxlLCByZW1vdmUgdGhlIHNhcHBseSBjYWxsczogZS5nLiByZXBsYWNlIHNhcHBseShkYWRhRnMsIGdldE4pIHdpdGggZ2V0TihkYWRhRnMpCmNvbG5hbWVzKHRyYWNrKSA8LSBjKCJpbnB1dCIsICJmaWx0ZXJlZCIsICJ0YWJsZWQiKQpyb3duYW1lcyh0cmFjaykgPC0gc2FtcGxlX25hbWVzCmhlYWQodHJhY2spCnNhdmUodHJhY2ssIGZpbGUgPSAidGFibGVfdHJhY2tfQTUxNUYtWV85MjZSLlJEYXRhIikKYGBgCgpBbmQgcmVtb3ZlIGNoaW1lcmFzIGFzIHRoZSBvdGhlciBwYXJ0IDoKYGBge3IgUmVtb3ZlIGNoaW1lcmFzLCBldmFsPSBGfQpzZXF0YWIubm9jaGltIDwtIHJlbW92ZUJpbWVyYURlbm92byhzZXF0YWIsIG1ldGhvZD0iY29uc2Vuc3VzIiwgbXVsdGl0aHJlYWQ9VFJVRSwgdmVyYm9zZT1UUlVFKQpkaW0oc2VxdGFiLm5vY2hpbSkKc3VtKHNlcXRhYi5ub2NoaW0pL3N1bShzZXF0YWIpCnNhdmVSRFMoc2VxdGFiLm5vY2hpbSwgcGFzdGUwKGRpcl9zZXFfcHJvY2Vzc2luZywic2VxdGFiLm5vY2hpbS5yZHMiKSkKYGBgCgoqKioKIyMjIyBUYXhvbm9teSBhc3NpZ25tZW50CgpZb3UgaGF2ZSBhbHJlYWR5IGxvYWQgdGhlIFNJTFZBIHJlZiBmaWxlcywgdGhlbiB5b3UgaGF2ZSB0byBhc3NpZ24gZnJvbSB0aGVtIHRoZSBzZXF1ZW5jZSB0YWJsZXMKYGBge3IgVGF4IGFzc2lnbm1lbnQsIGV2YWwgPSBGfQpsb2FkKGRpcl9zZXFfcHJvY2Vzc2luZyAsICJzZXF0YWIubm9jaGltLnJkcyIpCgpwYXRoX3JlZmVyZW5jZV9kYiA8LSBwYXN0ZTAoZGlyX3JlZmRiLCAic2lsdmFfbnJfdjEzMl90cmFpbl9zZXQuZmEuZ3oiKQpwYXRoX3NwZWNpZXNfZGIgICA8LSBwYXN0ZTAoZGlyX3JlZmRiLCAic2lsdmFfc3BlY2llc19hc3NpZ25tZW50X3YxMzIuZmEuZ3oiKQp0YXhhUkMgPC0gYXNzaWduVGF4b25vbXkoc2VxdGFiLm5vY2hpbSwgcGF0aF9yZWZlcmVuY2VfZGIsIHRyeVJDPVRSVUUpCnRheGFTcCA8LSBhZGRTcGVjaWVzKHRheGFSQywgcGF0aF9zcGVjaWVzX2RiKSAjIFRoaXMgc3RlcCBjYW4gYmUgdmVyeSBsb25nCgp0YXhhLnByaW50IDwtIHRheGFTcCAjIFJlbW92aW5nIHNlcXVlbmNlIHJvd25hbWVzIGZvciBkaXNwbGF5IG9ubHkKcm93bmFtZXModGF4YS5wcmludCkgPC0gTlVMTApoZWFkKHRheGEucHJpbnQpCgpzYXZlUkRTKHNlcXRhYi5ub2NoaW0sdGF4YVJDLCB0YXhhU3AsIGZpbGU9IHBhc3RlMChkaXJfc2VxX3Byb2Nlc3NpbmcsImRhZGEyX2ZpbGVzLnJkcyIpKQpgYGAKCioqKgo8YSBpZD0iUGFydCBJSTogUGh5bG9zZXEgcHJvY2VzcyI+PC9hPiAKCiMjIFBhcnQgSUk6IFBoeWxvc2VxIHByb2Nlc3MKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpOb3cgeW91IGNhbiBjcmVhdGUgeW91ciBwaHlsb3NlcSBvYmplY3Qgd2l0aCB5b3VyIGZpbHRlcmVkIGFuZCBhc3NpZ25lZCBzZXF1ZW5jZXMuIEJlZm9yZSBydW5uaW5nIHRoZSBwaHlsb3NlcSBwcm9jZXNzLCB5b3UgbmVlZCB0byBjbGVhbiB5b3VyIHdvcnNwYWNlIGluIG9yZGVyIHRvIGZyZWUgdGhlIHIgc3RhY2sgbWVtb3J5CgpgYGB7ciBzZXR1cDIgLCBlY2hvID0gRiwgd2FybmluZz1GLCBtZXNzYWdlID0gRiwgcmVzdWx0cyA9IEZ9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gRkFMU0UpCnJlbW92ZShsaXN0ID0gbHMoKSkKY3Jhbl9wYWNrYWdlcyAgIDwtIGMoImtuaXRyIiwgInBoeWxvc2VxR3JhcGhUZXN0IiwgInBoeWxvc2VxIiwgInNoaW55IiwgIm1pY3JvYmlvbWUiLAogICAgICAgICAgICAgICAgICAgICAidGlkeXZlcnNlIiwgIm1pbmlVSSIsICJjYXJldCIsICJwbHMiLCAiZTEwNzEiLCAiZ2dwbG90MiIsIAogICAgICAgICAgICAgICAgICAgICAicmFuZG9tRm9yZXN0IiwiZW50cm9wYXJ0IiwgInZlZ2FuIiwgInBseXIiLCAiZHBseXIiLCAiaGVyZSIsCiAgICAgICAgICAgICAgICAgICAgICJnZ3JlcGVsIiwgIm5sbWUiLCAiUi51dGlscyIsICJncmlkRXh0cmEiLCJncmlkIiwgImdvb2dsZWRyaXZlIiwgCiAgICAgICAgICAgICAgICAgICAgICJnb29nbGVzaGVldHMiLCAicGhhbmdvcm4iLCAiZGV2dG9vbHMiLCAicm1hcmtkb3duIiwgInN5cyIsCiAgICAgICAgICAgICAgICAgICAgICJyZXNoYXBlMiIsICJkZXZ0b29scyIsICJQTUEiLCJzdHJ1Y3RTU0kiLCJhZGU0IiwgImFwZSIsCiAgICAgICAgICAgICAgICAgICAgICJCaW9zdHJpbmdzIiwgImlncmFwaCIsICJnZ25ldHdvcmsiLCAiaW50ZXJncmFwaCIsICJpcHMiLAogICAgICAgICAgICAgICAgICAgICAic2NhbGVzIiwgImthYmxlRXh0cmEiLCAicGdpcm1lc3MiLCAidHJlZW1hcCIsICJrbml0ciIsImthYmxlRXh0cmEiLAogICAgICAgICAgICAgICAgICAgICAicnN0dWRpb2FwaSIgLCJkYXRhLnRhYmxlIiwiRFQiLCJwYW5kZXIiLCJmb3JtYXRSIiwiZ3JEZXZpY2VzIiwic3ZnUGFuWm9vbSIsCiAgICAgICAgICAgICAgICAgICAgICJSQ3VybCIsInBsb3RseSIsInBhaXJ3aXNlQWRvbmlzIiwgInN0cmluZ3IiKQpnaXRodWJfcGFja2FnZXMgPC0gYygiamZ1a3V5YW1hL3BoeWxvc2VxR3JhcGhUZXN0IikKYmlvY19wYWNrYWdlcyAgIDwtIGMoInBoeWxvc2VxIiwgImdlbmVmaWx0ZXIiLCAiaW1wdXRlIiwgImRhZGEyIiwgIkRFQ0lQSEVSIikKIyBJbnN0YWxsIENSQU4gcGFja2FnZXMgKGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZCkKI1NvbWUgcGFja2FnZXMgd291bGQgYmUgbm90IGF2YWlsYmFsZSBmb3IgeW91ciBSIHZlcnNpb24KaW5zdCA8LSBjcmFuX3BhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkKaWYgKGFueSghIGluc3QpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcyhjcmFuX3BhY2thZ2VzWyFpbnN0XSwgcmVwb3MgPSAiaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikgfQojIAppbnN0IDwtIGdpdGh1Yl9wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpCmlmIChhbnkoISBpbnN0KSkgewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihnaXRodWJfcGFja2FnZXNbIWluc3RdKSB9CgojIExvYWQgbGlicmFyaWVzCnNhcHBseShjKGNyYW5fcGFja2FnZXMsIGJpb2NfcGFja2FnZXMpLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCnNlc3Npb25JbmZvKCkKc2V0LnNlZWQoMTAwMCkKYGBgCgpBbmQgc2V0X3dkIGFnYWluIAoKYGBge3Igc2V0X3dkMiwgZWNobyA9IEYsIGV2YWwgPSBUfQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9IGdldHdkKCkpCnBhdGggPSBnZXR3ZCgpCiMgVGhpcyB3aWxsIHNldHdkIHRvIHdoZXJldmVyIHRoZSAuUm1kIGZpbGUgaXMgb3BlbmVkLgpkaXJfc2FtcGxlX3NlbGVjdGlvbiA8LSBwYXN0ZTAocGF0aCwiL2FuYWx5c2VzLzAxX3NlbGVjdF9zYW1wbGVzLyIpCmRpcl9zZXFfcHJvY2Vzc2luZyAgIDwtIHBhc3RlMChwYXRoLCIvYW5hbHlzZXMvMDJfcHJvY2Vzc19zZXF1ZW5jZXMvIikKZGlyX3RheGFfYXNzaWduICAgICAgPC0gcGFzdGUwKHBhdGgsIi9hbmFseXNlcy8wM19hc3NpZ25fdGF4b25vbXkvIikKZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy8iKQpkaXJfcHJpbWVycyAgIDwtIHBhc3RlMChwYXRoLCIvZGlyX2RhdGFfc291cmNlL3ByaW1lcnNfc2VxdWVuY2VzLyIpCmRpcl9yZWZkYiAgIDwtIHBhc3RlMChwYXRoLCIvZGlyX2RhdGFfc291cmNlL3JlZmVyZW5jZV9kYXRhYmFzZXMvIikKZGlyX2Zhc3RxX3NvdXJjZSA8LSBwYXN0ZTAocGF0aCwiL2Rpcl9kYXRhX3NvdXJjZS9zZXF1ZW5jZXMvIikKYGBgCgojIyMjIFBoeWxvc2VxIG9iamVjdCBjcmVhdGlvbgoKV2UgY2FuIGNyZWF0ZSBvdXIgcGh5bG9zZXEgb2JqZWN0IGZyb20gdGhlIHNlcXRhYi5ub2NoaW0gZmlsZSBjcmVhdGVkIHByZXZpb3VzbHkuCmBgYHtyIHBoeWxvc2VxX2NyZWF0aW9uICwgZXZhbD0gRn0KbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCJkYWRhMl9maWxlcy5yZHMiKSkKbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCJzZXF0YWIubm9jaGltXzUxNUYtWS45MjZSLlJEYXRhIikpCgpwcyA8LSBwaHlsb3NlcShvdHVfdGFibGUoc2VxdGFiLm5vY2hpbSwgdGF4YV9hcmVfcm93cz1GQUxTRSksdGF4X3RhYmxlKHRheGFSQykpIAojIFlvdSBjYW4gdXNlIHRheF90YWJsZSh0YXhhU3ApIGlmIHlvdSBuZWVkIHRoZSBhc3NpZ25tZW50IHVudGlsIHNwZWNpZXMgbGV2ZWwKYGBgCgpOb3csIHdlIHdpbGwgbW9kaWZ5IG91ciB0YWJsZSB3aXRoIEFTVnMgbmFtZXMgCgpgYGB7ciBBU1ZzIG5hbWVzLCAgZXZhbCA9IEZ9CmRuYSA8LSBCaW9zdHJpbmdzOjpETkFTdHJpbmdTZXQodGF4YV9uYW1lcyhwcykpCm5hbWVzKGRuYSkgPC0gdGF4YV9uYW1lcyhwcykKcHMgPC0gbWVyZ2VfcGh5bG9zZXEocHMsIGRuYSkKdGF4YV9uYW1lcyhwcykgPC0gcGFzdGUwKCJBU1YiLCBzZXEobnRheGEocHMpKSkKcHMKc2F2ZShwcywgdGF4YVJDLHNlcXRhYi5ub2NoaW0sIHNlcXRhYiwgZmlsZT1wYXN0ZTAoZGlyX3RheGFfYXNzaWduICwicHNfNTE1Ri1ZLjkyNlIuUkRhdGEiKSkKIyBGaXJzdCByZXN1bHRzIApudGF4YShwcykKbnNhbXBsZXMocHMpCnNhbXBsZV9uYW1lcyhwcylbMTo1XQpyYW5rX25hbWVzKHBzKQpvdHVfdGFibGUocHMpWzE6NSwgMTo1XQp0YXhfdGFibGUocHMpWzE6NSwgMTo2XQpgYGAKCgojIyMjIFByZXNlbnRhdGlvbiBvZiB0aGUgZW52ZGF0YQoKVGhlIGVudmRhdGEgaXMgY29uc3RpdHV0ZWQgb2YgdGhlIHNhbXBsaW5nIGRhdGEgZm9yIHRoZSBndXQsIGFsZ2FlIGFuZCB0dXJmIHNhbXBsZXMuCiogWyoqVGF4X2luZm9ybWF0aW9uKipde3RhcmdldD0iX2JsYW5rIn0gOiBUaGUgaW5mb3JtYXRpb25zIGNvbmNlcm5pbmcgdGhlIHNwZWNpZXMgYXJlIHdyaXR0ZW4gaW4gZGlmZmVyZW50IHdheXMgd2l0aCAqKnRheDEqKiBhcyB0aGUgU3BlY2llcyBnZW51cywgKip0YXgyKiogYXMgdGhlIFNwZWNpZXNfZ2VudXMgbm9tZW5jbGF0dXJlLCAqKnRheDMqKiBhcyB0aGUgU1BHX3ggd2hpY2ggaXMgdGhlIGNvcnJlc3BvbmRpbmcgdHdvIGZpcnN0IGxldHRlcnMgb2YgdGhlIHNwZWNpZXMgYW5kIHRoZSBmaXJzdCBvZiB0aGUgZ2VudXMgZm9sbG93ZWQgYnkgdGhlICp4KiBvZiB0aGUgc2FtcGxlZCBpbmRpdmlkdWFscyBpbiB0aGlzIHNwZWNpZXMuIFRoZSAqKnR5cGUqKiwgKipsaW5lYWdlKiosICoqT3JkZXIqKiwgKipGYW1pbHkqKiAsKipHZW51cyoqIGFuZCAqKlNwZWNpZXMqKiBhcmUgbWVudGlvbmVkLiAKCiogWyoqRGlldF9pbmZvcm1hdGlvbioqXXt0YXJnZXQ9Il9ibGFuayJ9OiBUaGUgRGlldCBpcyBtZW50aW9ubmVkIGF0IGhpZ2ggc2NhbGUgd2l0aCB0aGUgKipkaWV0MyoqIGFuZCBhdCBncmFudWxvdXMgc2NhbGVzIGZvbGxvd2luZyB0aGUgZWNvbG9naWNhbCB0cmFpdHMgaW4gW01vdWlsbG90IGV0IGFsLiwgKDIwMTQpXShodHRwczovL3d3dy5wbmFzLm9yZy9jb250ZW50LzExMS8zOC8xMzc1NykuIFRoZSAqKmRpZXQ0KiogbWVudGlvbm5lZCB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgaGVyYml2b3J5IGZvciB0aGUgU2NhcmlkYWUsIEFjYW50aHVyaWRhZSBhbmQgU2lnYW5pZGFlIHNwZWNpZXMuIEFsc28sIHRoZSB0cm9waGljIHBvc2l0aW9uIGlzIG1lbnRpb25uZWQgd2l0aCBbdGhlIEZpc2hCYXNlIHJlZmVyZW5jZV0oaHR0cHM6Ly93d3cuZmlzaGJhc2Uuc2Uvc2VhcmNoLnBocCkuCgoqIFsqKkluZGl2aWR1YWxfaW5mb3JtYXRpb24qKl17dGFyZ2V0PSJfYmxhbmsifTogRm9yIGVhY2ggaW5kaXZpZHVhbCwgdGhlIHdlaWdodCAqKm1hc3MqKiwgdG90YWwgKipsZW5ndGgqKiwgKipndXQgbWFzcyoqIGFuZCAqKnNleCoqIHdlcmUgb2J0YWluZWQuCgoqIFsqKlNpdGVfaW5mb3JtYXRpb24qKl17dGFyZ2V0PSJfYmxhbmsifTogKipTaXRlKiogd2l0aCB0aGUgKipHUFMgY29vcmRvbmF0ZXMqKiB3ZXJlIHRha2VuIGFuZCB0aGUgKipnZW9tb3JwaG9sb2d5Kiogd2VyZSBhdHRyaWJ1dGVkIHRvIHRoZSBjb25kaXRpb24gb2YgdGhlIHJlZWYuCgpgYGB7ciBlbnZkYXRhICwgZXZhbCA9IFQsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLmFsaWduID0gImNlbnRlciJ9CmVudmRhdGEgPC0gcmVhZC5jc3YyKHBhc3RlMChkaXJfcmVmZGIsICJlbnYuY3N2IikpCmNvbG5hbWVzKGVudmRhdGEpWzFdID0gIklEIgpkYXRhdGFibGUoZW52ZGF0YVstYygzLDYsMTAsIDEyKV0sIHJvd25hbWVzID0gRkFMU0UsIHdpZHRoID0gIjEwMCUiLAogICAgICAgICAgY29sbmFtZXMgPSBjKCJJRCIsICJTcGVjaWVzIiwiU3BlY2llcyBudW1iZXIiICwiQ29tcGFydG1lbnQiLCJPcmRlciIsIkZhbWlseSIsIkdlbnVzIiwiRGlldCBhYnJldmlhdGlvbiIsIkRpZXQgSGlnaCBzY2FsZSIsIkRpZXQgTG93IHNjYWxlIiwiVHJvcGhpYyBwb3NpdGlvbiIsICJNYXNzIChnKSIsIlRvdGFsIExlbmd0aCAoY20pIiwiR3V0IG1hc3MgKGcpIiwiU2V4IiwiU2l0ZSIsIlJlZWYgY29uZGl0aW9uIiwiR1BTIGxhdGl0dWRlIiwiR1BTIGxvbmdpdHVkZSIsICJJc2xhbmQiLCAiU3Vic3RyYXQiKSwgCiAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oc3R5bGUgPSAiY2FwdGlvbi1zaWRlOiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0b207IHRleHQtYWxpZ246IGxlZnQ7IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhYmxlOiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sdG9vbHM6OmVtKCJTYW1wbGUgcHJlc2VudGF0aW9uLiIpKSwgCiAgICAgICAgICBleHRlbnNpb25zID0gIkJ1dHRvbnMiLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1sZWZ0IiwgdGFyZ2V0cyA9IDApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAiQmxmcnRpcCIsIHBhZ2VMZW5ndGggPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aE1lbnUgPSBjKDUsIDEwLCAyNSwgNTApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCJjc3YiLCAiY29weSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFLCBzY3JvbGxDb2xsYXBzZSA9IFRSVUUpKQpgYGAKCkl0J3MganVzdCBhbiBwYXJlbnRoZXNpcyBmb3Igb3JkZXJpbmcgZW52ZGF0YSBkZXBlbmRpbmcgb2YgeW91ciBwaHlsb3NlcSBvYmplY3RzLiBJdCBpcyBhIHN0ZXAgYSBiaXQgYm9ycmluZyBidXQgbmVjZXNzYXJ5IGlmIHlvdXIgZW52IGZpbGUgaXMgbm90IHN5bmNocm8gd2l0aCB5b3VyIHBoeWxvc2VxIG9iamVjdCwgbWVhbmluZyB0aGF0IHRoZSBzYW1wbGVzIG5hbWVzIGluIHlvdXIgZW52IGZpbGUgYXJlIG5vdCB0aGUgc2FtZSB0aGF0IHlvdXIgc2FtcGxlIG5hbWVzIGluIHRoZSBwaHlsb3NlcSBvYmplY3QuIApGaXJzdCwgd2Ugd2lsbCBvcmRlciB0aGUgbmFtZXMKCmBgYHtyIE9yZGVyIHRoZSBuYW1lcyAsIGV2YWwgPSBGfQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJkYWRhMl9maWxlcy5SRGF0YSIpKQpub2NoaW1fbmFtZXMgPC0gcm93bmFtZXMoc2VxdGFiLm5vY2hpbSkKZW52X25hbWVzIDwtIGFzLmNoYXJhY3RlcihlbnZkYXRhJElEKQpgYGAKCgpOb3csIHRoZSBhaW0gaXMgdG8gaGF2ZSBleGFjdGx5IHRoZSBzYW1lIG5hbWVzIGluIHRoZSBwaHlsb3NlcSBvYmplY3QgYW5kIGluIHRoZSBlbnYgdGFibGUuIApgYGB7ciBUIG9yIEYgLCBldmFsPUYgfQpsZWN0dXJlIDwtIGNiaW5kKHNvcnQobm9jaGltX25hbWVzKSxzb3J0KGVudl9uYW1lcykpCmlkZW50aWNhbChsZWN0dXJlWywxXSwgbGVjdHVyZVssMl0pIApgYGAKSWYgaXQncyAqKlRydWUqKiwgeW91J3JlIG5hbWVzIGFyZSB0aGUgc2FtZSwgZGlyZWN0bHkgcGFzcyB0byB0aGUgbWVyZ2luZyBzdGVwOyBJZiAqKkZhbHNlKiosIHlvdSBoYXZlIHRvIHJlcGxhY2UgdGhlIGNvcnJlY3QgbmFtZXMuIEFsc28sIHlvdSBoYXZlIHRvIGNoZWNrIHlvdXIgZW52IGZpbGUgd2l0aCB0aGUgbmFtZXMgb2YgeW91ciBmaXNoIHNwZWNpZXMsIGdlbnVzIG9yIGZhbWlseSB3aGljaCBjb3VsZCBiZSBpbmNvcnJlY3QuIAoKYGBge3IgY2hlY2sgdGhlIG5hbWVzIG9mIHRoZSB0YXggZmlzaCwgZXZhbD0gRn0KbGV2ZWxzKGZhY3RvcihlbnZkYXRhJGZhbWlseSkpCmxldmVscyhmYWN0b3IoZW52ZGF0YSRzcGVjaWVzKSkKYGBgCgojIyMjIE1lcmdpbmcgZGF0YSAKCk5vdyB0aGF0IHRoZSBzZXF0YWIgYW5kIHRoZSBlbnZkYXRhIGFyZSBjb3JyZXNwb25kaW5nLCB3ZSB3aWxsIG1lcmdlIHRoZW0gaW50byBwaHlsb3NlcSBvYmplY3QuCgpgYGB7ciBNZXJnZSBlbnZkYXRhIGFuZCBwaHlsb3NlcSwgZXZhbD1GfQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sInBzXzUxNUYtWS45MjZSLlJEYXRhIikpCmVudmRhdGEgPC0gcmVhZC5jc3YyKHBhc3RlMChkaXJfcmVmZGIsICJlbnYuY3N2IikpCmNvbG5hbWVzKGVudmRhdGEpWzFdID0gIklEIgpEQVQgPC0gc2FtcGxlX2RhdGEoZW52ZGF0YSkKREFUCnNvcnQoc2FtcGxlX25hbWVzKERBVCkpID09IHNvcnQoc2FtcGxlX25hbWVzKHBzKSkgIyBtdXN0IGJlIHRydWUgdG8gYmUgbWVyZ2VkCgpwczE8LSBtZXJnZV9waHlsb3NlcShwcywgREFUKQpwczEKc2F2ZShwczEsIGVudmRhdGEsZmlsZT1wYXN0ZTAoZGlyX3RheGFfYXNzaWduICwicHMxXzUxNUYtWS45MjZSLlJEYXRhIikpCmBgYAoKUGxvdCB0aGUgc2FtcGxlIG1pbmltdW0gQVNWIAoKYGBge3Igc2FtcGxlIG1pbmltdW0gQVNWICwgZXZhbCA9IEZ9Cm1pbihyb3dTdW1zKHBzMUBvdHVfdGFibGVALkRhdGEpKQpyZWFkc3Vtc2RmID0gZGF0YS5mcmFtZShucmVhZHMgPSBzb3J0KHRheGFfc3VtcyhwczEpLFRSVUUpLCBzb3J0ZWQgPSAxOm50YXhhKHBzMSksIHR5cGUgPSAiQVNWcyIpCnJlYWRzdW1zZGYgPSByYmluZChyZWFkc3Vtc2RmLCBkYXRhLmZyYW1lKG5yZWFkcyA9IHNvcnQoc2FtcGxlX3N1bXMocHMxKSwgVFJVRSksIHNvcnRlZCA9IDE6bnNhbXBsZXMocHMxKSwgdHlwZSA9ICJTYW1wbGVzIikpCgp0aXRsZSA9ICJUb3RhbCBudW1iZXIgb2YgcmVhZHMiCnBkZihmaWxlID0gcGFzdGUwKGRpcl9xdWFsaXR5X3Bsb3RzLCAidG90YWxfbnVtYmVyX29mX3JlYWRzLnBkZiIpLCBoZSA9IDcsIHdpID0gNykKcCA9IGdncGxvdChyZWFkc3Vtc2RmLCBhZXMoeCA9IHNvcnRlZCwgeSA9IG5yZWFkcykpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpCnAgKyBnZ3RpdGxlKHRpdGxlKSArIHNjYWxlX3lfbG9nMTAoKSArIGZhY2V0X3dyYXAofnR5cGUsIDEsIHNjYWxlcyA9ICJmcmVlIikKZGV2Lm9mZigpCmBgYAoKIyMjIyBQaHlsb3NlcSBjcmVhdGlvbgoKV2Ugd2lsbCBmaWx0ZXIgb3VyIHBzMSB0byBvbmx5IGtlZXAgdGhlICoqUHJva2FyeW90ZXMqKgoKYGBge3IgUHJva2FyeW90ZXNfc2VsZWN0aW9uLCBldmFsID0gRn0KbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAicHMxXzUxNUYtWS45MjZSLlJEYXRhIikpCnBzX3NleV9wcm9rYSA8LSBzdWJzZXRfdGF4YShwc19zZXkgLCBLaW5nZG9tICVpbiUgYygiQXJjaGFlYSIsICJCYWN0ZXJpYSIpKQpzYXZlKHBzX3NleV9wcm9rYSwgZmlsZSA9IHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJwc19zZXlfcHJva2EuUkRhdGEiKSkKYGBgCgpUaGVuLCB3ZSB3aWxsIG9idGFpbiB0aGUgcGh5bG9nZW5ldGljIGRpc3RhbmNlcyBiZXR3ZWVuIEFTVnMKIFRoZSB0cmVlIHdhcyBvYnRhaW5lZCBhZnRlciBhbGlnbmluZyB0aGUgc2VxdWVuY2VzIG9uIG1vdGh1ciBhbmQgd2FzIG5hbWVzICJTZXkudHJlZSIgYW5kIHdhcyBsb2FkIGluIHRoZSAqXGRpcl90YXhhX2Fzc2lnbiogZm9sZGVyLiBUaGUgYXNzaWdubWVudCB3YXMgbWFkZSBhZ2FpbnN0IHRoZSBBUkIgZGF0YWJhc2UgYXZhaWxhYmxlIG9uIFNJTFZBIGRhdGFiYXNlIHJlZmVyZW5jZSAodjEzMikgYW5kIHByb2NlZWRlZCBvbiBbKipNb3RodXIqKl0oaHR0cHM6Ly9hZW0uYXNtLm9yZy9jb250ZW50Lzc1LzIzLzc1MzcpIHBsYXRmb3JtLgogCmBgYHtyIHJlYWRfdHJlZSAsIGV2YWwgPSBGfQpzZXlfdHJlZSA8LSByZWFkLnRyZWUocGFzdGUoZGlyX3RheGFfYXNzaWduLCAiU2V5LnRyZWUiKSkKc2V5X3RyZWUyIDwtIHJvb3Qoc2V5X3RyZWUsICJBU1Y0MDYxOSIsIHJlc29sdmUucm9vdCA9IFQpCnNleV90cmVlMiA8LSBkcm9wLnRpcChzZXlfdHJlZTIsIkFTVjQwNjE5IiApICMgVG8gZGVsZXRlIHRoZSBvdXRncm91cCBBU1YKCmxpYnJhcnkocGljYW50ZSkKY2FsMTwtbWFrZUNocm9ub3NDYWxpYihzZXlfdHJlZTIsIG5vZGUgPSAicm9vdCIsIGFnZS5taW4gPSAxLCBhZ2UubWF4ID0gMSwgaW50ZXJhY3RpdmUgPSBGQUxTRSwgc29mdC5ib3VuZHMgPSBGQUxTRSkgI2NhbGlicmF0aW9uIGZvciB1bHRyYW1ldHJpYyBicmFuY2hzLgpzZXlfY2hyb25vZ3JhbW1lPC1jaHJvbm9zKHNleV90cmVlMiwgbGFtYmRhPTAsIG1vZGVsID0gImRpc2NyZXRlIiwgY2FsPWNhbDEsIHF1aWV0ID0gRkFMU0UsIGNvbnRyb2w9Y2hyb25vcy5jb250cm9sKG5iLnJhdGUuY2F0PTEpKQpzYXZlKHNleV9jaHJvbm9ncmFtbWUgLGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduICwic2V5X2Nocm9ub2dyYW1tZS5SZGF0YSIpKQoKcHNfc2V5X3RyZWUgPC0gbWVyZ2VfcGh5bG9zZXEocHNfc2V5X3Byb2thLCBzZXlfdHJlZTIpCnNhdmUocHNfc2V5X3RyZWUsIGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAicHNfc2V5X3RyZWUuUkRhdGEiKSkKYGBgCiAKTm93IHRoYXQgdGhlIHBoeWxvc2VxIGlzIG9ubHkgbWFkZSBieSBQcm9rYXJ5b3RlcyB3aGljaCBwaHlsb2dlbmV0aWMgZGlzdGFuY2VzIGFyZSBhc3NvY2lhdGVkLCB3ZSB3aWxsIGZpbmFsbHkgZmlsdGVyIGFsbCBvcmdhbmVscyAoQ2hsb3JvcGxhc3QgYW5kIE1pdG9jaG9uZHJpYSkgYW5kIHBvdGVudGlhbCBjb250YW1pbmFudHMgb2YgdGhlIGV4Y3RyYWN0aW9uIGtpdHMgYW5kIHN0ZXBzIG9mIGFtcGxpZmljYXRpb24gYXMgbWVudGlvbm5lZCBpbiBbU2FsdGVyIGV0IGFsLiwgMjAxNF0oaHR0cHM6Ly9ibWNiaW9sLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEyOTE1LTAxNC0wMDg3LXopLgoKIyMjIyBDbGVhbiB0aGUgcGh5bG9zZXEgb2JqZWN0CgpgYGB7ciBGaWx0ZXIgdGhlIGNvbnRhbWluYW50cyBhbmQgb3JnYW5lbHMsIGV2YWwgPSBGfQpjb250X2xpc3QgPC0gcmVhZC5jc3YoIi9Vc2Vycy9tYXJpZS1jaGFybG90dGVjaGV1dGluL0RyaXZlL1RoZXNpcy9TZXljaGVsbGVzL1dQNS4zX2RhdGEvZGF0YV9zb3VyY2VzL3JlZmVyZW5jZV9kYXRhYmFzZXMvbGlzdF9wb3RlbnRpYWxfY29udGFtaW5hbnRzLmNzdiIpCmNvbnRhbWluYW50IDwtIGNvbnRfbGlzdCRHZW51cwpzZXlfZmluYWwgPC0gc3Vic2V0X3RheGEocHNfc2V5X3RyZWUsIE9yZGVyICE9ICJDaGxvcm9wbGFzdCIpCnNleV9maW5hbCA8LSBzdWJzZXRfdGF4YShzZXlfZmluYWwgLCBGYW1pbHkgIT0gIk1pdG9jaG9uZHJpYSIpCnNleV9jb250YW1pbmFudCA8LSBzdWJzZXRfdGF4YShzZXlfZmluYWwgLCBHZW51cyAlaW4lIGNvbnRhbWluYW50KQpzYXZlKHNleV9jb250YW1pbmFudCAsIGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5X2NvbnRhbWluYW50LlJkYXRhIikpCnNleV9maW5hbCA8LSBzdWJzZXRfdGF4YShzZXlfZmluYWwgLCAhR2VudXMgJWluJSBjb250YW1pbmFudCkKc2F2ZShzZXlfZmluYWwsIGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCJzZXlfZmluYWwuUkRhdGEiKSkKc2V5cmZmX2ZpbmFsICA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKHNleV9maW5hbCkgPj0gbWluKHNhbXBsZV9zdW1zKHNleV9maW5hbCkpICwgc2V5X2ZpbmFsKQpzZXlyZmZfZmluYWwgPC0gcmFyZWZ5X2V2ZW5fZGVwdGgoc2V5cmZmX2ZpbmFsLCBzYW1wbGUuc2l6ZSA9IG1pbihzYW1wbGVfc3VtcyhzZXlfZmluYWwpKSkKc2F2ZShzZXlyZmZfZmluYWwsIGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5cmZmX2ZpbmFsLlJEYXRhIikpCmBgYAoKTm93IHdlIGhhdmUgdGhlIGZpbmFsIHBoeWxvc2VxIGZvciBhbGwgdGhlIHNhbXBsZXMsIHdlIGNhbiBzdWJzZXQgdGhlIHBoeWxvc2VxIG9iamVjdCBmb3IgdGhlIGd1dCwgdGhlIGFsZ2FlIGFuZCB0aGUgdHVyZiBhbmQgcmFyZWZ5IHRoZW0uIFRvIGJlIHN1cmUgdGhhdCB0aGUgbWluaW1hbCBhYnVuZGFuY2Ugb2YgdGhlIGRhdGEgc2V0IGlzIGVub3VnaCB0byBjYXB0dXJlIGFsbCB0aGUgZGl2ZXJzaXR5LCB3ZSB1c2UgdGhlIGZ1bmN0aW9uICoqZ2dyYXJlKCkqKiAKCmBgYHtyIGdncmFyZSBmdW5jdGlvbiwgZXZhbCA9IFR9CmdncmFyZSA8LSBmdW5jdGlvbihwaHlzZXFfb2JqZWN0LCBzdGVwID0gMTAsIGxhYmVsID0gTlVMTCwgY29sb3IgPSBOVUxMLCBwbG90ID0gVFJVRSwgcGFyYWxsZWwgPSBGQUxTRSwgc2UgPSBUUlVFKSB7CgogIHggPC0gbWV0aG9kczo6YXMocGh5bG9zZXE6Om90dV90YWJsZShwaHlzZXFfb2JqZWN0KSwgIm1hdHJpeCIpCiAgaWYgKHBoeWxvc2VxOjp0YXhhX2FyZV9yb3dzKHBoeXNlcV9vYmplY3QpKSB7IHggPC0gdCh4KSB9CiMjIFRoaXMgc2NyaXB0IGlzIGFkYXB0ZWQgZnJvbSB2ZWdhbiBgcmFyZWN1cnZlYCBmdW5jdGlvbgogIHRvdCA8LSByb3dTdW1zKHgpCiAgUyA8LSByb3dTdW1zKHggPiAwKQogIG5yIDwtIG5yb3coeCkKCiAgcmFyZWZ1biA8LSBmdW5jdGlvbihpKSB7CiAgICBjYXQocGFzdGUoInJhcmVmeWluZyBzYW1wbGUiLCByb3duYW1lcyh4KVtpXSksIHNlcCA9ICJcbiIpCiAgICBuIDwtIHNlcSgxLCB0b3RbaV0sIGJ5ID0gc3RlcCkKICAgIGlmIChuW2xlbmd0aChuKV0gIT0gdG90W2ldKSB7CiAgICAgIG4gPC0gYyhuLCB0b3RbaV0pCiAgICB9CiAgICB5IDwtIHZlZ2FuOjpyYXJlZnkoeFtpLCAsZHJvcCA9IEZBTFNFXSwgbiwgc2UgPSBzZSkKICAgIGlmIChucm93KHkpICE9IDEpIHsKICAgICAgcm93bmFtZXMoeSkgPC0gYygiLlMiLCAiLnNlIikKICAgICAgcmV0dXJuKGRhdGEuZnJhbWUodCh5KSwgU2l6ZSA9IG4sIFNhbXBsZSA9IHJvd25hbWVzKHgpW2ldKSkKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybihkYXRhLmZyYW1lKC5TID0geVsxLCBdLCBTaXplID0gbiwgU2FtcGxlID0gcm93bmFtZXMoeClbaV0pKQogICAgfQogIH0KICBpZiAocGFyYWxsZWwpIHsKICAgIG91dCA8LSBwYXJhbGxlbDo6bWNsYXBwbHkoc2VxX2xlbihuciksIHJhcmVmdW4sIG1jLnByZXNjaGVkdWxlID0gRkFMU0UpCiAgfSBlbHNlIHsKICAgIG91dCA8LSBsYXBwbHkoc2VxX2xlbihuciksIHJhcmVmdW4pCiAgfQogIGRmIDwtIGRvLmNhbGwocmJpbmQsIG91dCkKCiAgIyBHZXQgc2FtcGxlIGRhdGEKICBpZiAoIWlzLm51bGwocGh5bG9zZXE6OnNhbXBsZV9kYXRhKHBoeXNlcV9vYmplY3QsIEZBTFNFKSkpIHsKICAgIHNkZiA8LSBtZXRob2RzOjphcyhwaHlsb3NlcTo6c2FtcGxlX2RhdGEocGh5c2VxX29iamVjdCksICJkYXRhLmZyYW1lIikKICAgIHNkZiRTYW1wbGUgPC0gcm93bmFtZXMoc2RmKQogICAgZGF0YSA8LSBtZXJnZShkZiwgc2RmLCBieSA9ICJTYW1wbGUiKQogICAgbGFiZWxzIDwtIGRhdGEuZnJhbWUoeCA9IHRvdCwgeSA9IFMsIFNhbXBsZSA9IHJvd25hbWVzKHgpKQogICAgbGFiZWxzIDwtIG1lcmdlKGxhYmVscywgc2RmLCBieSA9ICJTYW1wbGUiKQogIH0KCiAgIyBBZGQsIGFueSBjdXN0b20tc3VwcGxpZWQgcGxvdC1tYXBwZWQgdmFyaWFibGVzCiAgaWYgKCBsZW5ndGgoY29sb3IpID4gMSApIHsKICAgIGRhdGEkY29sb3IgPC0gY29sb3IKICAgIG5hbWVzKGRhdGEpW25hbWVzKGRhdGEpID09ICJjb2xvciJdIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShjb2xvcikpCiAgICBjb2xvciA8LSBkZXBhcnNlKHN1YnN0aXR1dGUoY29sb3IpKQogIH0KCiAgaWYgKCBsZW5ndGgobGFiZWwpID4gMSApIHsKICAgIGxhYmVscyRsYWJlbCA8LSBsYWJlbAogICAgbmFtZXMobGFiZWxzKVtuYW1lcyhsYWJlbHMpID09ICJsYWJlbCJdIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShsYWJlbCkpCiAgICBsYWJlbCA8LSBkZXBhcnNlKHN1YnN0aXR1dGUobGFiZWwpKQogIH0KCiAgcCA8LSBnZ3Bsb3QyOjpnZ3Bsb3QoZGF0YSA9IGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90Mjo6YWVzX3N0cmluZyh4ID0gIlNpemUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICIuUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJTYW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcikpCgogIHAgPC0gcCArIGdncGxvdDI6OmxhYnMoeCA9ICJTZXF1ZW5jZSBTYW1wbGUgU2l6ZSIsIHkgPSAiU3BlY2llcyBSaWNobmVzcyIpCgogIGlmICghaXMubnVsbChsYWJlbCkpIHsKICAgIHAgPC0gcCArIGdncGxvdDI6Omdlb21fdGV4dChkYXRhID0gbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdDI6OmFlc19zdHJpbmcoeCA9ICJ4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAieSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGxhYmVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvciksCiAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDQsIGhqdXN0ID0gMCkKICB9CgogIHAgPC0gcCArIGdncGxvdDI6Omdlb21fbGluZSgpCiAgaWYgKHNlKSB7ICMjIGFkZCBzdGFuZGFyZCBlcnJvciBpZiBhdmFpbGFibGUKICAgIHAgPC0gcCArCiAgICAgIGdncGxvdDI6Omdlb21fcmliYm9uKGdncGxvdDI6OmFlc19zdHJpbmcoeW1pbiA9ICIuUyAtIC5zZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9ICIuUyArIC5zZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjb2xvciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKQogIH0KICBpZiAocGxvdCkgewogICAgcGxvdChwKQogIH0KICBpbnZpc2libGUocCkKfQpgYGAKQW5kIG5vdyB1c2UgaXQgYW5kIGNyZWF0ZSB0aGUgcGh5bG9zZXEgb2JqZWN0cwoKIyMjIyBTdWJzZXQgdGhlIHBoeWxvc2VxIG9iamVjdHMKCmBgYHtyIHBoeWxvc2VxIHN1YnNldCwgZXZhbD0gVCwgd2FybmluZyA9IEZBTFNFLG1lc3NhZ2UgPSBGLCByZXN1bHRzID0gImhpZGUifQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlfZmluYWwuUkRhdGEiKSkKIyBGaXNoIHBzIApzZXlfZ3V0IDwtIHN1YnNldF9zYW1wbGVzKHNleV9maW5hbCwgdHlwZSA9PSAiZ3V0IikKc2V5X2d1dCA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoc2V5X2d1dEBvdHVfdGFibGUpPjApKSwgc2V5X2d1dCkKc2F2ZShzZXlfZ3V0LCBmaWxlID0gcGFzdGUwKGRpcl90YXhhX2Fzc2lnbiwgInNleV9ndXQuUkRhdGEiKSkKc29ydChzYW1wbGVfc3VtcyhzZXlfZ3V0KSkKc2V0LnNlZWQoMTAwMDApCnBfZ3V0IDwtIGdncmFyZShzZXlfZ3V0LCBzdGVwID0gNTAwLCBjb2xvciA9ICJnZW9tb3JwaG8iLCBsYWJlbCA9ICJ0YXgxIiwgc2UgPSBGQUxTRSkKc2V5cmZmX2d1dCA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKHNleV9ndXQpID49IG1pbihzYW1wbGVfc3VtcyhzZXlfZ3V0KSkgLCBzZXlfZ3V0KQpzZXlyZmZfZ3V0IDwtIHJhcmVmeV9ldmVuX2RlcHRoKHNleXJmZl9ndXQsIHNhbXBsZS5zaXplID0gbWluKHNhbXBsZV9zdW1zKHNleV9ndXQpKSkKc2F2ZShzZXlyZmZfZ3V0LCBmaWxlID0gcGFzdGUwKGRpcl90YXhhX2Fzc2lnbiwgInNleXJmZl9ndXQuUkRhdGEiKSkKIyBBbGdhZSBwcyAKc2V5X2FsZ2FlIDwtIHN1YnNldF9zYW1wbGVzKHNleV9maW5hbCwgdGF4MSAlaW4lIGMoIm1hY3JvYWxnYWUiLCAidHVyZiIpKQpzZXlfYWxnYWUgPC0gcHJ1bmVfdGF4YShuYW1lcyh3aGljaChjb2xTdW1zKHNleV9hbGdhZUBvdHVfdGFibGUpPjApKSwgc2V5X2FsZ2FlKQpzYXZlKHNleV9hbGdhZSwgZmlsZSA9IHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlfYWxnYWUuUkRhdGEiKSkKc2V0LnNlZWQoMTAwMDApCnBfYWxnYWUgPC0gZ2dyYXJlKHNleV9hbGdhZSwgc3RlcCA9IDUwMCwgY29sb3IgPSAiZ2VvbW9ycGhvIiwgbGFiZWwgPSAidGF4MSIsIHNlID0gRkFMU0UpCnNleXJmZl9hbGdhZSA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKHNleV9hbGdhZSkgPj0gbWluKHNhbXBsZV9zdW1zKHNleV9hbGdhZSkpICwgc2V5X2FsZ2FlKQpzZXlyZmZfYWxnYWUgPC0gcmFyZWZ5X2V2ZW5fZGVwdGgoc2V5cmZmX2FsZ2FlLCBzYW1wbGUuc2l6ZSA9IG1pbihzYW1wbGVfc3VtcyhzZXlfYWxnYWUpKSkKc2F2ZShzZXlyZmZfYWxnYWUsIGZpbGUgPSBwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5cmZmX2FsZ2FlLlJEYXRhIikpCmBgYAoKKioqCjxhIGlkPSJQYXJ0IElJSTogRmlzaCBDb21tdW5pdHkgQ29tcG9zaXRpb24gYmV0d2VlbiBSZWVmcyI+PC9hPiAgCgojIyBQYXJ0IElJSTogRmlzaCBDb21tdW5pdHkgQ29tcG9zaXRpb24gYmV0d2VlbiBSZWVmcwpbYmFjayB0byB0b3BdKCNiYWNrIHRvIHRvcCkKCkhlcmUgYWdhaW4sIHdlIHdpbGwgcmVtb3ZlIGFsbCB0aGUgb2JqZWN0IHRvIGNsZWFuIHRoZSBtZW1vcnkgCmBgYHtyIHNldHVwMyAsIGVjaG8gPSBGICwgZXZhbCA9IFQsICBtZXNzYWdlPSBGLHdhcm5pbmc9RiwgcmVzdWx0cz0gRn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGV2YWwgPSBGQUxTRSkKcmVtb3ZlKGxpc3QgPSBscygpKQpjcmFuX3BhY2thZ2VzICAgPC0gYygia25pdHIiLCAicGh5bG9zZXFHcmFwaFRlc3QiLCAicGh5bG9zZXEiLCAic2hpbnkiLCAibWljcm9iaW9tZSIsCiAgICAgICAgICAgICAgICAgICAgICJ0aWR5dmVyc2UiLCAibWluaVVJIiwgImNhcmV0IiwgInBscyIsICJlMTA3MSIsICJnZ3Bsb3QyIiwgCiAgICAgICAgICAgICAgICAgICAgICJyYW5kb21Gb3Jlc3QiLCJlbnRyb3BhcnQiLCAidmVnYW4iLCAicGx5ciIsICJkcGx5ciIsICJoZXJlIiwKICAgICAgICAgICAgICAgICAgICAgImdncmVwZWwiLCAibmxtZSIsICJSLnV0aWxzIiwgImdyaWRFeHRyYSIsImdyaWQiLCAiZ29vZ2xlZHJpdmUiLAogICAgICAgICAgICAgICAgICAgICAiZ29vZ2xlc2hlZXRzIiwgInBoYW5nb3JuIiwgImRldnRvb2xzIiwgInJtYXJrZG93biIsICJzeXMiLAogICAgICAgICAgICAgICAgICAgICAicmVzaGFwZTIiLCAiZGV2dG9vbHMiLCAiUE1BIiwic3RydWN0U1NJIiwiYWRlNCIsICJhcGUiLAogICAgICAgICAgICAgICAgICAgICAiQmlvc3RyaW5ncyIsICJpZ3JhcGgiLCAiZ2duZXR3b3JrIiwgImludGVyZ3JhcGgiLCAiaXBzIiwKICAgICAgICAgICAgICAgICAgICAgInNjYWxlcyIsICJrYWJsZUV4dHJhIiwgInBnaXJtZXNzIiwgInRyZWVtYXAiLCAia25pdHIiLCJrYWJsZUV4dHJhIiwKICAgICAgICAgICAgICAgICAgICAgInJzdHVkaW9hcGkiICwiZGF0YS50YWJsZSIsIkRUIiwicGFuZGVyIiwiZm9ybWF0UiIsImdyRGV2aWNlcyIsInN2Z1Bhblpvb20iLAogICAgICAgICAgICAgICAgICAgICAiUkN1cmwiLCJwbG90bHkiLCJwYWlyd2lzZUFkb25pcyIsICJzdHJpbmdyIikKZ2l0aHViX3BhY2thZ2VzIDwtIGMoImpmdWt1eWFtYS9waHlsb3NlcUdyYXBoVGVzdCIpCmJpb2NfcGFja2FnZXMgICA8LSBjKCJwaHlsb3NlcSIsICJnZW5lZmlsdGVyIiwgImltcHV0ZSIsICJkYWRhMiIsICJERUNJUEhFUiIpCiMgSW5zdGFsbCBDUkFOIHBhY2thZ2VzIChpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQpCiNTb21lIHBhY2thZ2VzIHdvdWxkIGJlIG5vdCBhdmFpbGJhbGUgZm9yIHlvdXIgUiB2ZXJzaW9uCmluc3QgPC0gY3Jhbl9wYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpCmlmIChhbnkoISBpbnN0KSkgewogIGluc3RhbGwucGFja2FnZXMoY3Jhbl9wYWNrYWdlc1shaW5zdF0sIHJlcG9zID0gImh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpIH0KIyAKaW5zdCA8LSBnaXRodWJfcGFja2FnZXMgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKQppZiAoYW55KCEgaW5zdCkpIHsKICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoZ2l0aHViX3BhY2thZ2VzWyFpbnN0XSkgfQoKIyBMb2FkIGxpYnJhcmllcwpzYXBwbHkoYyhjcmFuX3BhY2thZ2VzLCBiaW9jX3BhY2thZ2VzKSwgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpzZXNzaW9uSW5mbygpCnNldC5zZWVkKDEwMDApCmBgYAoKQW5kIHNldF93ZCBhZ2FpbiAKCmBgYHtyIHNldF93ZDMsIGVjaG8gPSBGLCBldmFsID0gVCwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBnZXR3ZCgpKQpwYXRoID0gZ2V0d2QoKQojIFRoaXMgd2lsbCBzZXR3ZCB0byB3aGVyZXZlciB0aGUgLlJtZCBmaWxlIGlzIG9wZW5lZC4KZGlyX3NhbXBsZV9zZWxlY3Rpb24gPC0gcGFzdGUwKHBhdGgsIi9hbmFseXNlcy8wMV9zZWxlY3Rfc2FtcGxlcy8iKQpkaXJfc2VxX3Byb2Nlc3NpbmcgICA8LSBwYXN0ZTAocGF0aCwiL2FuYWx5c2VzLzAyX3Byb2Nlc3Nfc2VxdWVuY2VzLyIpCmRpcl90YXhhX2Fzc2lnbiAgICAgIDwtIHBhc3RlMChwYXRoLCIvYW5hbHlzZXMvMDNfYXNzaWduX3RheG9ub215LyIpCmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvIikKZGlyX3ByaW1lcnMgICA8LSBwYXN0ZTAocGF0aCwiL2Rpcl9kYXRhX3NvdXJjZS9wcmltZXJzX3NlcXVlbmNlcy8iKQpkaXJfcmVmZGIgICA8LSBwYXN0ZTAocGF0aCwiL2Rpcl9kYXRhX3NvdXJjZS9yZWZlcmVuY2VfZGF0YWJhc2VzLyIpCmRpcl9mYXN0cV9zb3VyY2UgPC0gcGFzdGUwKHBhdGgsIi9kaXJfZGF0YV9zb3VyY2Uvc2VxdWVuY2VzLyIpCmBgYAoKSW4gdGhpcyBpcyBwYXJ0LCB3ZSB3aWxsIGZvY3VzIG9uIG91ciBzYW1wbGluZyBkYXRhc2V0IGFuZCBhbmFseXplIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGhvc3RzIGJldHdlZW4gdGhlIElScyBhbmQgSFJzLgoKYGBge3IgbG9hZF9maWxlcywgZXZhbCA9IFQsIHJlc3VsdHM9ImhpZGUiLCB3YXJuaW5nPSBGfQplbnZkYXRhIDwtIHJlYWQuY3N2MihwYXN0ZTAoZGlyX3JlZmRiLCAiZW52LmNzdiIpKQpjb2xuYW1lcyhlbnZkYXRhKVsxXSA9ICJJRCIKbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5X2d1dC5SRGF0YSIpKQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlfZmluYWwuUkRhdGEiKSkKYGBgCgpXZSB3aWxsIGZpcnN0IHdyaXRlIHRoZSB0YWJsZSBvZiB0aGUgc3BlY2llcyBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBkaWV0LgoKYGBge3IgdGFibGVfc3BfZGlldCwgZXZhbD0gVCwgd2FybmluZyA9IEZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgbWVzc2FnZT1GfQpkaWV0X3NwIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZW52ZGF0YSRkaWV0NCwgZW52ZGF0YSR0YXgxKSlbd2hpY2goYXMuZGF0YS5mcmFtZSh0YWJsZShlbnZkYXRhJGRpZXQ0LCBlbnZkYXRhJHRheDEpKVssM10+IDApLF1bLGMoMSwyKV0Kc3BfcmVlZiA8LSB0YWJsZShlbnZkYXRhJHRheDEsIGVudmRhdGEkZ2VvbW9ycGhvKQpzcF9yZWVmIDwtIGNiaW5kKGFzLmRhdGEuZnJhbWUoc3BfcmVlZlssMV0pLCBhcy5kYXRhLmZyYW1lKHNwX3JlZWZbLDJdKSkKdGFibGVfZGlldF9zcCA8LSBjYmluZChkaWV0X3NwWywyXSxkaWV0X3NwWywxXSxzcF9yZWVmWyxjKDEsMildKQoKdGFibGVfdG9fcHJpbnQgPC0gcmJpbmQodGFibGVfZGlldF9zcFstYygyNiwzNyksXSwgdGFibGVfZGlldF9zcFtjKDI2LDM3KSxdKQpkYXRhdGFibGUodGFibGVfdG9fcHJpbnQsIHJvd25hbWVzID0gRiwgd2lkdGggPSAiMTAwJSIsCiAgICAgICAgICBjb2xuYW1lcyA9IGMoIlNwZWNpZXMiLCAiRGlldCIsICJIUiIsIklSIiksCiAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oc3R5bGUgPSAiY2FwdGlvbi1zaWRlOiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0b207IHRleHQtYWxpZ246IGxlZnQ7IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRhYmxlOiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sdG9vbHM6OmVtKCJTYW1wbGluZyB0YWJsZSBvZiB0aGUgc3BlY2llcyBhbmQgZGlldCBiZXR3ZWVuIHJlZWZzLiIpKSwgCiAgICAgICAgICBleHRlbnNpb25zID0gIkJ1dHRvbnMiLCAKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KGNvbHVtbkRlZnMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsaXN0KGNsYXNzTmFtZSA9ICJkdC1sZWZ0IiwgdGFyZ2V0cyA9IDApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAiQmxmcnRpcCIsIHBhZ2VMZW5ndGggPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aE1lbnUgPSBjKDUsIDEwLCAyNSwgNTApLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCJjc3YiLCAiY29weSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFLCBzY3JvbGxDb2xsYXBzZSA9IFRSVUUpKQpgYGAKCiMjIyMjIFBDb0Egb24gZmlzaCBjb21tdW5pdHkKClRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsaW5nIHNldCBpcyBhIGZpcnN0IHJlc3VsdCBzaG93aW5nIHRoZSBpbmZsdWVuY2Ugb2YgdGhlIHNoaWZ0IG9uIHRoZSBmaXNoIGNvbW11bml0aWVzLiBIb3cgYXJlIHRoZXkgZGlzdHJpYnV0ZWQ/CgpgYGB7ciBQQ29BX2ZhbWlseSwgZXZhbD0gVCAsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ICJjZW50ZXIifQpzYW1wX2RhdGEgPC0gZW52ZGF0YVtlbnZkYXRhJHR5cGU9PSJndXQiLF0KZmFtX3RhYiA8LSB0YWJsZShzYW1wX2RhdGEkc2l0ZSxzYW1wX2RhdGEkZmFtaWx5KQoKIyBUcmFuc2Zvcm0gdG8gbG9nCmZhbS5sb2cgPC0gbG9nMXAoZmFtX3RhYikgICMgRXF1aXZhbGVudDogbG9nKGZhbV90YWIgKyAxKQojIFByaW5jaXBhbCBjb29yZGluYXRlIGFuYWx5c2lzIGFuZCBzaW1wbGUgb3JkaW5hdGlvbiBwbG90CmZhbS5EIDwtIHZlZ2Rpc3QoZmFtLmxvZywgImJyYXkiKQpyZXMgPC0gcGNvYShmYW0uRCkKI3JlcyR2YWx1ZXMKYmlwbG90KHJlcywgZmFtLmxvZykKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSkgIyA1Ny44ICUKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSkgIyAyNiAlCgpzaXRlMSA8LSBjKCJDMSIsIkMyIiwiQzMiLCJDNCIsICJNMSIsIk0yIiwiTTMiKQpzaXRlMiA8LSBjKHJlcCgiY29yYWwiLCA0KSwgcmVwKCJtYWNyb2FsZ2FsIiwzKSkKc2l0ZV9kYXRhIDwtIGNiaW5kKHNpdGUxLHNpdGUyKQpjb2xuYW1lcyhzaXRlX2RhdGEpIDwtIGMoInNpdGUiLCAiZ2VvbW9ycGhvIikKc2l0ZV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoc2l0ZV9kYXRhKQoKYWRvbmlzKGZhbS5EIH4gZ2VvbW9ycGhvLCBkYXRhID0gc2l0ZV9kYXRhKQpiZXRhX3JlZWYgPC0gYmV0YWRpc3BlcihmYW0uRCwgc2l0ZV9kYXRhJGdlb21vcnBobykKcGVybXV0ZXN0KGJldGFfcmVlZikKYGBgCgpOb3csIHdlIHdpbGwgZG8gdGhlIHNhbWUgb24gdHJvcGhpYyBzcnR1Y3R1cmUgd2l0aCB0aGUgZGlldAoKYGBge3IgUENvQV9kaWV0LGV2YWw9IFQgLCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQpzYW1wX2RhdGEgPC0gZW52ZGF0YVtlbnZkYXRhJHR5cGU9PSJndXQiLF0KZGlldF90YWIgPC0gdGFibGUoc2FtcF9kYXRhJHNpdGUsc2FtcF9kYXRhJGRpZXQ0KQojIFRyYW5zZm9ybSB0byBsb2cKZGlldC5sb2cgPC0gbG9nMXAoZGlldF90YWIpICAjIEVxdWl2YWxlbnQ6IGxvZyhkaWV0X3RhYiArIDEpCiMgUHJpbmNpcGFsIGNvb3JkaW5hdGUgYW5hbHlzaXMgYW5kIHNpbXBsZSBvcmRpbmF0aW9uIHBsb3QKZGlldC5EIDwtIHZlZ2Rpc3QoZGlldC5sb2csICJicmF5IikKcmVzIDwtIHBjb2EoZGlldC5EKQojcmVzJHZhbHVlcwpwYXIobWZyb3c9YygxLDIpKQpiaXBsb3QocmVzLCBkaWV0LmxvZykKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSkgIyA3NC4xICUKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSkgIyAxNy44ICUKCnNpdGUxIDwtIGMoIkMxIiwiQzIiLCJDMyIsIkM0IiwgIk0xIiwiTTIiLCJNMyIpCnNpdGUyIDwtIGMocmVwKCJjb3JhbCIsIDQpLCByZXAoIm1hY3JvYWxnYWwiLDMpKQpzaXRlX2RhdGEgPC0gY2JpbmQoc2l0ZTEsc2l0ZTIpCmNvbG5hbWVzKHNpdGVfZGF0YSkgPC0gYygic2l0ZSIsICJnZW9tb3JwaG8iKQpzaXRlX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShzaXRlX2RhdGEpCgphZG9uaXMoZGlldC5EIH4gZ2VvbW9ycGhvLCBkYXRhID0gc2l0ZV9kYXRhKQpiZXRhX3JlZWYgPC0gYmV0YWRpc3BlcihkaWV0LkQsIHNpdGVfZGF0YSRnZW9tb3JwaG8pCnBlcm11dGVzdChiZXRhX3JlZWYpCmBgYAoKQmVjYXVzZSB3ZSB3aWxsIGZvY3VzIG91ciBzdXRkeSBvbiBoZXJiaXZvcmVzIGFuZCBpbnZlcnRpdm9yZXMsIHdlIG5lZWQgdG8ga25vdyBpZiBmYW1pbGllcyBhcmUgZXF1YWxseSBkaXN0cmlidXRlZC4KCmBgYHtyIFBDb0FfaW52LGV2YWw9IFQgLCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRixmaWcuYWxpZ249ImNlbnRlciJ9CnNhbXBfZGF0YV9pbnYgPC0gc2FtcF9kYXRhW3NhbXBfZGF0YSRkaWV0NCA9PSAiTW9iaWxlIGludmVydGVicmF0ZSIsXQpmYW1fdGFiIDwtIHRhYmxlKHNhbXBfZGF0YV9pbnYkc2l0ZSxzYW1wX2RhdGFfaW52JGZhbWlseSkKIyBUcmFuc2Zvcm0gdG8gbG9nCmZhbS5sb2cgPC0gbG9nMXAoZmFtX3RhYikgICMgRXF1aXZhbGVudDogbG9nKGZhbV90YWIgKyAxKQojIFByaW5jaXBhbCBjb29yZGluYXRlIGFuYWx5c2lzIGFuZCBzaW1wbGUgb3JkaW5hdGlvbiBwbG90CmZhbS5EIDwtIHZlZ2Rpc3QoZmFtLmxvZywgImJyYXkiKQpyZXMgPC0gcGNvYShmYW0uRCkKI3JlcyR2YWx1ZXMKYmlwbG90KHJlcywgZmFtLmxvZykKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSkgIyA1Ny44ICUKI3JvdW5kKHJlcyR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSkgIyAyNiAlCgpzaXRlMSA8LSBjKCJDMSIsIkMyIiwiQzMiLCJDNCIsICJNMSIsIk0yIiwiTTMiKQpzaXRlMiA8LSBjKHJlcCgiY29yYWwiLCA0KSwgcmVwKCJtYWNyb2FsZ2FsIiwzKSkKc2l0ZV9kYXRhIDwtIGNiaW5kKHNpdGUxLHNpdGUyKQpjb2xuYW1lcyhzaXRlX2RhdGEpIDwtIGMoInNpdGUiLCAiZ2VvbW9ycGhvIikKc2l0ZV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoc2l0ZV9kYXRhKQoKYWRvbmlzKGZhbS5EIH4gZ2VvbW9ycGhvLCBkYXRhID0gc2l0ZV9kYXRhKQpiZXRhX3JlZWYgPC0gYmV0YWRpc3BlcihmYW0uRCwgc2l0ZV9kYXRhJGdlb21vcnBobykKcGVybXV0ZXN0KGJldGFfcmVlZikKYGBgCgoqKioKPGEgaWQ9IlBhcnQgSVY6IERldGVybWluYXRpb24gYW5kIGRlc2NyaXB0aW9uIG9mIHRoZSBlbnRlcmljIGFuZCBhbGdhbCBjb3JlIG1pY3JvYmlvbWVzIj48L2E+ICAKCiMjIFBhcnQgSVY6IERldGVybWluYXRpb24gYW5kIGRlc2NyaXB0aW9uIG9mIHRoZSBlbnRlcmljIGFuZCBhbGdhbCBjb3JlIG1pY3JvYmlvbWVzCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKIyMjIENvbG9ycwoKTWljcm9iaWFsIGNvbW11bml0eSBvZiBmaXNoIGlzIHZlcnkgaGlnaCBhbmQgaXQgaXMgdmVyeSBkaWZmaWN1bHQgdG8gZGlzY2VybiBsZXNzIHRoYW4gMTAgdGF4YS4gVGhhdCdzIHdoeSwgd2Uga2VwdCB0aGUgc2FtZSBjb2xvciBmb3IgdGhlIHNhbWUgdGF4YSwgaW4gb3JkZXIgdG8gYmUgYWJsZSB0byBjb21wYXJlIHRoZSBncmFwaHMgYmV0d2VlbiBjb21wYXJ0ZW10biwgZGlldCBvciBmaXNoIGZhbWlsaWVzLiBPZiBjb3Vyc2UsIGlmIHlvdXIgYXJlIG9ubHkgaW50ZXJlc3RlZCBpbiBzb21lIHRheGEsIGJldHRlciBjaG9vc2UgZmV3IGNvbG9ycy4gRm9yIHRoZSBiaWdnZXIgdGFibGUgKCppLmUqIHRheCB0YWJsZSBhdCBPcmRlciBsZXZlbCksICoqZGlzdGluY3RDb2xvclBhbGV0dGUoKSoqIGNvdWxkIGJlIHZlcnkgdXNlZnVsIGJ1dCBiZSBhd2FyZWQgdGhhdCBjb2xvcnMgYXJlIG5vdCByZXBlYXRlZC4gIEhlcmUgaXMgdGhlIGNvZGUgOiAKCmBgYHtyIGNvbG9ycyAsIGVjaG8gPSBUICwgZXZhbCA9IFR9CnBoeWx1bV9jb2xvcnMgPC0gYygnQWNpZG9iYWN0ZXJpYSc9J2xhdmVuZGVyYmx1c2g0JywKICAgICAgICAgICAgICAgICAgICdBY3Rpbm9iYWN0ZXJpYSc9J2RhcmtibHVlJywKICAgICAgICAgICAgICAgICAgICdBcm1hdGltb25hZGV0ZXMnPSdjYWRldGJsdWUzJywKICAgICAgICAgICAgICAgICAgICdCYWN0ZXJvaWRldGVzJz0nY29ybmZsb3dlcmJsdWUnLAogICAgICAgICAgICAgICAgICAgJ0NhbGRpdHJpY2hhZW90YSc9J2F6dXJlMycsCiAgICAgICAgICAgICAgICAgICAnQ2hsb3JvZmxleGknPScjRENFMUQyJywKICAgICAgICAgICAgICAgICAgICdDeWFub2JhY3RlcmlhJz0nI0RFNjU1NCcsCiAgICAgICAgICAgICAgICAgICAnRGFkYWJhY3RlcmlhJz0nYnJvd24yJywKICAgICAgICAgICAgICAgICAgICdEZWZlcnJpYmFjdGVyZXMnPSdkYXJrc2xhdGVncmF5MScsCiAgICAgICAgICAgICAgICAgICAnRGVpbm9jb2NjdXMtVGhlcm11cyc9J3NhbG1vbjQnLAogICAgICAgICAgICAgICAgICAgJ0RlcGVuZGVudGlhZSc9J3NhbmR5YnJvd24nLAogICAgICAgICAgICAgICAgICAgJ0Vwc2lsb25iYWN0ZXJhZW90YSc9J2RhcmtzbGF0ZWJsdWUnLAogICAgICAgICAgICAgICAgICAgJ0VsdXNpbWljcm9iaWEnPSdwbHVtMScsCiAgICAgICAgICAgICAgICAgICAnRXVyeWFyY2hhZW90YSc9J2hvdHBpbms0JywKICAgICAgICAgICAgICAgICAgICdGaXJtaWN1dGVzJz0nYnJvd240JywKICAgICAgICAgICAgICAgICAgICdGdXNvYmFjdGVyaWEnPSdvcmFuZ2UnLAogICAgICAgICAgICAgICAgICAgJ0dlbW1hdGltb25hZGV0ZXMnPSdkYXJrb2xpdmVncmVlbicsCiAgICAgICAgICAgICAgICAgICAnS2lyaXRpbWF0aWVsbGFlb3RhJz0nZGFya2toYWtpJywKICAgICAgICAgICAgICAgICAgICdNYXJpbmltaWNyb2JpYV8oU0FSNDA2X2NsYWRlKSc9J2Rhcmtnb2xkZW5yb2Q0JywKICAgICAgICAgICAgICAgICAgICdMYXRlc2NpYmFjdGVyaWEnPSdkYXJrc2VhZ3JlZW4yJywKICAgICAgICAgICAgICAgICAgICdMZW50aXNwaGFlcmFlJz0nZGFya3NlYWdyZWVuNCcsCiAgICAgICAgICAgICAgICAgICAnUGF0ZXNjaWJhY3RlcmlhJz0nZGFya3R1cnF1b2lzZScsCiAgICAgICAgICAgICAgICAgICAnUGxhbmN0b215Y2V0ZXMnPSdkYXJrc2xhdGVncmF5JywKICAgICAgICAgICAgICAgICAgICdQcm90ZW9iYWN0ZXJpYSc9J2FxdWFtYXJpbmU0JywKICAgICAgICAgICAgICAgICAgICdTcGlyb2NoYWV0ZXMnPSdkYXJrb2xpdmVncmVlbjMnLAogICAgICAgICAgICAgICAgICAgJ1RlbmVyaWN1dGVzJz0nI0NBOEVBNycsCiAgICAgICAgICAgICAgICAgICAnVGhhdW1hcmNoYWVvdGEnPSdnb2xkMycsCiAgICAgICAgICAgICAgICAgICAnVmVycnVjb21pY3JvYmlhJz0nZGFya2dyZWVuJywKICAgICAgICAgICAgICAgICAgICdXUFMtMic9J3RoaXN0bGUyJywKICAgICAgICAgICAgICAgICAgICdPdGhlcic9ICdibGFjaycsCiAgICAgICAgICAgICAgICAgICAnWi1PdGhlcicgPSAnYmxhY2snKQoKY2xhc3NfY29sb3JzIDwtIGMoIkFjaWRpbWljcm9iaWlhIj0iZGFya3NhbG1vbiIsCiAgICAgICAgICAgICAgICAgICJBY2lkb2JhY3RlcmlpYSI9ImxhdmVuZGVyYmx1c2g0IiwKICAgICAgICAgICAgICAgICAgIkFjdGlub2JhY3RlcmlhIj0iZGFya2JsdWUiLAogICAgICAgICAgICAgICAgICAiQWxwaGFwcm90ZW9iYWN0ZXJpYSI9ImxpZ2h0c2VhZ3JlZW4iLAogICAgICAgICAgICAgICAgICAiQmFiZWxpYWUiPSJwZWFjaHB1ZmYiLAogICAgICAgICAgICAgICAgICAiQW5hZXJvbGluZWFlIj0idG9tYXRvMiIsCiAgICAgICAgICAgICAgICAgICJCYWNpbGxpIj0iYnJvd240IiwKICAgICAgICAgICAgICAgICAgIkJhY3Rlcm9pZGlhIj0iY29ybmZsb3dlcmJsdWUiLAogICAgICAgICAgICAgICAgICAiQnJhY2h5c3BpcmFlIj0iZGFya29saXZlZ3JlZW4yIiwKICAgICAgICAgICAgICAgICAgIkNhbXB5bG9iYWN0ZXJpYSI9InJveWFsYmx1ZSIsCiAgICAgICAgICAgICAgICAgICJDbG9zdHJpZGlhIj0ib3JhbmdlMyIsCiAgICAgICAgICAgICAgICAgICJDb3Jpb2JhY3RlcmlpYSI9ImRlZXBza3libHVlNCIsCiAgICAgICAgICAgICAgICAgICJEZWZlcnJpYmFjdGVyZXMiPSJkYXJrc2xhdGVncmF5MSIsCiAgICAgICAgICAgICAgICAgICJEZWlub2NvY2NpIj0ic2t5Ymx1ZTMiLAogICAgICAgICAgICAgICAgICAiRGVsdGFwcm90ZW9iYWN0ZXJpYSI9InNreWJsdWU0IiwKICAgICAgICAgICAgICAgICAgIkVyeXNpcGVsb3RyaWNoaWEiPSJ5ZWxsb3ciLAogICAgICAgICAgICAgICAgICAiRnVzb2JhY3RlcmlpYSI9Im9yYW5nZSIsCiAgICAgICAgICAgICAgICAgICJGaW1icmlpbW9uYWRpYSIgPSAiZGFya3NlYWdyZWVuIiwKICAgICAgICAgICAgICAgICAgIkdhbW1hcHJvdGVvYmFjdGVyaWEiPSJhcXVhbWFyaW5lNCIsCiAgICAgICAgICAgICAgICAgICJLaXJpdGltYXRpZWxsYWUiPSJkYXJrZ3JheSIsCiAgICAgICAgICAgICAgICAgICJMZW50aXNwaGFlcmlhIj0iZGFya3NlYWdyZWVuNCIsCiAgICAgICAgICAgICAgICAgICJNaWNyb2dlbm9tYXRpYSI9InNlYXNoZWxsMyIsCiAgICAgICAgICAgICAgICAgICJNb2xsaWN1dGVzIj0iI0NBOEVBNyIsCiAgICAgICAgICAgICAgICAgICJOZWdhdGl2aWN1dGVzIj0icGFsZXZpb2xldHJlZDQiLAogICAgICAgICAgICAgICAgICAiTml0cm9zb3NwaGFlcmlhIj0ic2FuZHlicm93biIsCiAgICAgICAgICAgICAgICAgICJPeHlwaG90b2JhY3RlcmlhIj0iI0RFNjU1NCIsCiAgICAgICAgICAgICAgICAgICJQaHljaXNwaGFlcmFlIj0icm9zeWJyb3duNCIsCiAgICAgICAgICAgICAgICAgICJQbGFuY3RvbXljZXRhY2lhIj0iZGFya3NsYXRlZ3JheSIsCiAgICAgICAgICAgICAgICAgICJSaG9kb3RoZXJtaWEiPSJjb3Juc2lsazMiLAogICAgICAgICAgICAgICAgICAiU3Bpcm9jaGFldGlhIj0iZGFya29saXZlZ3JlZW4zIiwKICAgICAgICAgICAgICAgICAgIlRoZXJtb2FuYWVyb2JhY3VsaWEiPSJwdXJwbGUiLAogICAgICAgICAgICAgICAgICAiVGhlcm1vbGVvcGhpbGlhIj0iZGVlcHBpbms0IiwKICAgICAgICAgICAgICAgICAgIlZlcnJ1Y29taWNyb2JpYWUiPSJkYXJrZ3JlZW4iKQoKI2xpYnJhcnkocmFuZG9tY29sb1IpCiNuIDwtIGxlbmd0aChsZXZlbHMoY29yZV9waHlzZXFfb3JkZXIkT3JkZXIpKQojb3JkZXJfY29sb3JzIDwtIGRpc3RpbmN0Q29sb3JQYWxldHRlKG4pCmBgYAoKCioqKgoKTGV0J3MgYW5hbHl6ZSBvdXIgZGF0YSBwcmV2aW91c2x5IHByb2NlZWRlZC4gSW4gb3JkZXIgdG8gZGVzY3JpbWluZSB3aGljaCBBU1ZzIGFyZSByYXJlICh0cmFuc2llbnRzKSBhbmQgd2hpY2ggd291bGQgYmUgY29uc2lkZXJlZCBhcyBwZXJtYW5lbnQgKGNvcmUpLCB3ZSB1c2UgYSBkaXNwZXJzaW9uIGluZGV4IGZvciBlYWNoIEFTViBhbmQgY29tcGFyZSBpdCBhdCB0aGUgUG9pc3NvbiBkaXN0cmlidXRpb24gdG8gZGV0ZXJtaW5lIHdoaWNoIEFTVnMgYXJlIHNpZ25pZmNhbnRseSByYW5kb21seSBkaXN0cmlidXRlZCAodHJhbnNpYW50KSBhbmQgd2hpY2ggYXJlIG5vdCAoY29yZSkgZm9sbG93aW5nIHRoZSBtZXRob2Qgb2YgW0ZpbGxvbCBldCBhbC4gKDIwMTYpXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL2lzbWVqMjAxNTE0MykuCgoqKiogCiMjIyBQYXJ0IElWYTogRW50ZXJpYyBjb3JlIG1pY3JvYmlvbWUKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpXZSBjcmVhdGUgYSBuZXcgZm9sZGVyIGZvciB0aGUgZW50ZXJpYyBtaWNyb2Jpb21lIG9mIHJlZWYgZmlzaCAKYW5kIGRldGVybWluZSB0aGUgY29yZS4KCmBgYHtyIGVudGVyaWMgY29yZSB3ZCwgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nPUYsIG1lc3NhZ2UgPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0Zpc2gvQ29yZS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlfZ3V0LlJEYXRhIikpCmxvYWQocGFzdGUwKGRpcl90YXhhX2Fzc2lnbiwgInNleXJmZl9ndXQuUkRhdGEiKSkKYGBgCgojIyMjIENvcmUgZGV0ZXJtaW5hdGlvbgoKYGBge3IgZW50ZXJpYyBjb3JlIGRldGVybWluYXRpb24sIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KbGlicmFyeShsYWJkc3YpCm90dV90YWJsZSA8LSBzZXlyZmZfZ3V0QG90dV90YWJsZUAuRGF0YQphYnVvY2NwbG90X290dSA8LSBhYnVvY2Mob3R1X3RhYmxlKQojc3ViX29iamVjdHMgb2YgYWJ1b2NjIG9iamVjdHMKc3RyKGFidW9jY3Bsb3Rfb3R1KQojIHRyYW5zZm9ybSBzcGMucGx0IHZlY3RvciBpbnRvIHRhYmxlIGluIG9yZGVyIHRvIGNhbGN1bGF0ZSBzcGVjaWZpYyByaWNobmVzcwpyaWNobmVzc19vdHUgPC0gZGF0YS5mcmFtZShhYnVvY2NwbG90X290dSRzcGMucGx0KQojIG9jY3VyZW5jZSBvZiBlYWNoIE9UVQpvdHVfb2NjdXJlbmNlIDwtIGRhdGEuZnJhbWUoYWJ1b2NjcGxvdF9vdHUkcGx0LnNwYykKbWVhbi5hYnVuX290dSA8LSBjb2xTdW1zKG90dV90YWJsZSkvb3R1X29jY3VyZW5jZQpzcXVhcmVfb3R1IDwtIG90dV90YWJsZV4yCnNzX290dSA8LSBkYXRhLmZyYW1lKGNvbFN1bXMoc3F1YXJlX290dSkpCiMgVmFyaWFuY2UgY2FsY3VsYXRpb24KdmFyaWFuY2Vfb3R1PXNzX290dS9vdHVfb2NjdXJlbmNlLW1lYW4uYWJ1bl9vdHVeMgpkaXNwX290dSA8LSAodmFyaWFuY2Vfb3R1L21lYW4uYWJ1bl9vdHUpKm90dV9vY2N1cmVuY2UKIyBJQyBjYWxjdWxhdGlvbiBmb3IgUG9pc3NvbiBkaXN0cmlidXRpb24gdXNpbmcgQ2hpIHNxdWFyZSBkaXN0cmlidXRpb24gKHZhbHVlIGFuZCBmb3JtdWxhIHdpdGhpbiBaYXIgcDU3NCkKbGlicmFyeShlcGl0b29scykKcG9pc2ljX290dSA9IHBvaXMuZXhhY3Qob3R1X29jY3VyZW5jZSwgY29uZi5sZXZlbCA9IDAuOTUpCmd1dF9kc3RhdF9vdHUgPC0gY2JpbmQobWVhbi5hYnVuX290dSwgZGlzcF9vdHUsIG90dV9vY2N1cmVuY2UsIHBvaXNpY19vdHUpCm5hbWVzKGd1dF9kc3RhdF9vdHUpIDwtIGMoImF2ZXJhZ2UiLCJkaXNwIiwgIm9jY3VyZW5jZSIsICJ4IiwgInB0IiwgInJhdGUiLCAibG93ZXIiLCAidXBwZXIiLCAicHJvYiIpCnNhdmUoZ3V0X2RzdGF0X290dSwgZmlsZT1wYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJndXRfc2V5X2RzdGF0X2Fzdi5SRGF0YSIpKQojIFNlbGVjdGlvbiBvZiBjb3JlIEFTVnMKZ3V0X3NleV9jb3JlX290dSA8LSBndXRfZHN0YXRfb3R1W2d1dF9kc3RhdF9vdHUkZGlzcCA+IGd1dF9kc3RhdF9vdHUkdXBwZXIsXQpndXRfc2V5X2NvcmVfb3R1IDwtIG5hLmV4Y2x1ZGUoZ3V0X3NleV9jb3JlX290dSkKZ3V0X3RheCA8LSBkYXRhLmZyYW1lKHNleXJmZl9ndXRAdGF4X3RhYmxlQC5EYXRhKQpndXRfc2V5X2NvcmVfb3R1JHRheCA8LSBndXRfdGF4W3Jvd25hbWVzKGd1dF90YXgpICVpbiUgcm93Lm5hbWVzKGd1dF9zZXlfY29yZV9vdHUpLDZdCmd1dF9zZXlfY29yZV9vdHUkcGh5bHVtIDwtIGd1dF90YXhbcm93bmFtZXMoZ3V0X3RheCkgJWluJSByb3cubmFtZXMoZ3V0X3NleV9jb3JlX290dSksMl0Kc2F2ZShndXRfc2V5X2NvcmVfb3R1LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCJndXRfc2V5X2NvcmVfb3R1LlJkYXRhIikpCgpzZXlfZ3V0X2NvcmUgPC1wcnVuZV90YXhhKHJvd25hbWVzKGd1dF9zZXlfY29yZV9vdHUpLCBzZXlyZmZfZ3V0KQpzYXZlKHNleV9ndXRfY29yZSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNleV9ndXRfY29yZS5SRGF0YSIpKQpgYGAKClRvIGJsYXN0IHRoZSByZWFkcyBvZiB0aGUgY29yZSwgd2UgbmVlZCB0byBnZW5lcmF0ZSBhIGZhc3RhIGZpbGUgd2l0aCB0aGUgZnVuY3Rpb24gYHdyaXRlWFN0cmluZ1NldCgpYC4KCmBgYHtyIGZhc3RhIGVudGVyaWMgZmlsZSwgZWNobyA9IEYsIGV2YWwgPSBGLCB3YXJuaW5nPUYsIG1lc3NhZ2UgPSBGfQpndXRfbmFtZXMgPC0gY29sbmFtZXMoc2V5X2d1dF9jb3JlQG90dV90YWJsZSkKZ3V0X3RyZWUgPC0gc3Vic2V0X3RheGEoc2V5X2d1dF9jb3JlLCByb3duYW1lcyhzZXlfZ3V0X2NvcmVAdGF4X3RhYmxlKSAlaW4lIGd1dF9uYW1lcykKZ3V0X3RyZWUKQmlvc3RyaW5nczo6d3JpdGVYU3RyaW5nU2V0KHNleV9ndXRfY29yZUByZWZzZXEsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsInNleV9ndXRfY29yZS5mYXN0YSIpKQpgYGAKCiMjIyMgQ29tcG9zaXRpb24gb2YgdGhlIGNvcmUKCmBgYHtyIGd1dCBjb21wb3NpdGlvbiBzdGFja3Bsb3QsIGVjaG8gPSBGLCBldmFsID0gVCwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KbGlicmFyeShkcGx5cikKZ3V0X2NvcmVfb3JkZXIgPC0gc2V5X2d1dF9jb3JlICU+JQogIHRheF9nbG9tKHRheHJhbmsgPSAiT3JkZXIiKSAlPiUgICAgICAgICAgICAgICAgICAgICAjIGFnZ2xvbWVyYXRlIGF0IHBoeWx1bSBsZXZlbAogIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGZ1bmN0aW9uKHgpIHt4L3N1bSh4KX0gKSAlPiUgIyBUcmFuc2Zvcm0gdG8gcmVsLiBhYnVuZGFuY2UKICBwc21lbHQoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTWVsdCB0byBsb25nIGZvcm1hdAogIGZpbHRlcihBYnVuZGFuY2UgPiAwLjAyKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgIyBGaWx0ZXIgb3V0IGxvdyBhYnVuZGFuY2UgdGF4YQogIGFycmFuZ2UoT3JkZXIpICAgICAgCgpzYXZlKGd1dF9jb3JlX29yZGVyICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImd1dF9jb3JlX29yZGVyLlJEYXRhIikpCmBgYAoKClBsb3QgYSB0cmVlbWFwIG9mIHRoZSBjb3JlIHRoYW5rcyB0byB0aGUgYHRyZWVtYXAoKWAgZnVuY3Rpb24gZm9yIHRoZSBtYWluIGNvbnRyaWJ1dG9yIG9mIHRoZSBjb3JlLiAKCmBgYHtyIHRyZWVtYXAgb2YgdGhlIGVudGVyaWMgY29yZSAsIGV2YWw9IFQgLCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSAiY2VudGVyIiB9Cmd1dF9jb3JlX29yZGVyJFBoeWx1bSA9IGFzLmNoYXJhY3RlcihndXRfY29yZV9vcmRlciRQaHlsdW0pICMgQXZvaWQgZXJyb3IgbWVzc2FnZSB3aXRoIGZhY3RvciBmb3IgbmV4dCBzdGVwCnNvcnQodGFibGUoZmFjdG9yKGd1dF9jb3JlX29yZGVyJFBoeWx1bSkpLCBUKQpndXRfY29yZV9vcmRlclshZ3V0X2NvcmVfb3JkZXIkUGh5bHVtICVpbiUgYygiUHJvdGVvYmFjdGVyaWEiLCJCYWN0ZXJvaWRldGVzIiwiQ3lhbm9iYWN0ZXJpYSIsIkZpcm1pY3V0ZXMiLCJQbGFuY3RvbXljZXRlcyIsICJTcGlyb2NoYWV0ZXMiLCAiVmVycnVjb21pY3JvYmlhIiwiRnVzb2JhY3RlcmlhIiwiVGVuZXJpY3V0ZXMiKSx3aGljaChuYW1lcyhndXRfY29yZV9vcmRlcikgPT0gIlBoeWx1bSIsIFQpXSA8LSAiT3RoZXIiICNDaGFuZ2UgcGh5bHVtIHRvIG90aGVyIGZvciB0aG9zZSBub3QgaW5jbHVkZWQgaW4gdGhlIGxpc3QKCmdyb3VwIDwtICBndXRfY29yZV9vcmRlciRQaHlsdW0Kc3ViZ3JvdXAgPC0gZ3V0X2NvcmVfb3JkZXIkT3JkZXIKdmFsdWUgPC0gZ3V0X2NvcmVfb3JkZXIkQWJ1bmRhbmNlCgpndXRfY29yZV90cmVlbWFwX2RhdGE9ZGF0YS5mcmFtZShncm91cCxzdWJncm91cCx2YWx1ZSkKCmxpYnJhcnkodHJlZW1hcCkKZ3V0X2NvcmVfdHJlZW1hcCA8LSB0cmVlbWFwKGd1dF9jb3JlX3RyZWVtYXBfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4PWMoImdyb3VwIiwic3ViZ3JvdXAiKSwgdlNpemUgPSAidmFsdWUiLCB0eXBlID0gImluZGV4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRjb2xvci5sYWJlbHM9Yygid2hpdGUiLCJibGFjayIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUubGFiZWxzPWMoMTIpLGJnLmxhYmVscz1jKCJ0cmFuc3BhcmVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UubGFiZWxzPWMoMiwzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlci5jb2w9YygiYmxhY2siLCJ3aGl0ZSIpLCBib3JkZXIubHdkcz1jKDQsMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24ubGFiZWxzPWxpc3QoYygiY2VudGVyIiwgImNlbnRlciIpLGMoImxlZnQiLCAiYm90dG9tIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9IlNleWNoZWxsZXMgRW50ZXJpYyBDb3JlIFRyZWVtYXAiLGZvbnRzaXplLnRpdGxlPTEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhbWlseS50aXRsZSA9InNlcmlmIikKCmBgYAoKYW5kIHZpc3VhbGl6ZSB0aGUgcmVsYXRpdmUgY29udHJpYnV0aW9uIG9mIHRoZSBkaWZmZXJlbnQgdGF4YSAod2l0aCB0aGUgYGZpbGw9YCBhcmd1bWVudCBmb3IgdGhlIGxldmVsIG9mIHRoZSB0YXhvbm9teSB5b3Ugd2FudCByZXByZXNlbnQpIGZvciB0aGUgZGlmZmVyZW50IHJlZWYgY29uZGl0aW9uIG9yIHNpdGUgd2l0aCB0aGUgYXJndW1lbnQgYHg9YC4KCipFeCogOiBUaGUgY29tcG9zaXRpb24gb2YgdGhlIGVudGVyaWMgY29yZSBtaWNyb2Jpb21lIGJldHdlZW4gcmVlZiBmaXNoIGZhbWlsaWVzIGF0IHBoeWx1bSBsZXZlbC4gCgpgYGB7ciBzdGFja2VkcGxvdCBvZiB0aGUgZW50ZXJpYyBjb3JlLCBlY2hvPSBGLCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciIgfQpndXRfY29yZV9vcmRlciRQaHlsdW0gPC0gc3RyX3JlcGxhY2VfYWxsKGd1dF9jb3JlX29yZGVyJFBoeWx1bSxjKCJPdGhlciIgPSAiWi1PdGhlciIpKQoKZ2dwbG90KGd1dF9jb3JlX29yZGVyLCBhZXMoeCA9IGZhbWlseSAsIHkgPSBBYnVuZGFuY2UsIGZpbGwgPSBQaHlsdW0pKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiKSArIAogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSAoT3JkZXIgPiAyJSkiKSArCiAgeGxhYigiRmFtaWx5IikrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKyAjcmVtb3ZlIHRoZSBzcGFjZSBiZWxvdyB0aGUgMCBvZiB0aGUgeSBheGlzIGluIHRoZSBncmFwaAogIGdndGl0bGUoIlBoeWx1bSBDb21wb3NpdGlvbiBvZiBDb3JlIEVudGVyaWMgTWljcm9iaW9tZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwaHlsdW1fY29sb3JzKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwKSwgCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDE1KSwgCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFtaWx5ID0gInNlcmlmIiwgYW5nbGUgPSA0NSx2anVzdCA9IDAuNjUpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLCBzaXplID0gMTMpLCAKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsIHNpemUgPSAxNSksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYW1pbHkgPSAic2VyaWYiKSkKYGBgCgojIyMjIENvcmUgcmF0aW8KClRvIGhhdmUgYSByZXByZXNlbnRhdGlvbiBvZiB0aGUgc2l6ZSBvZiB0aGUgY29yZSBpbiB0aGUgZW50aXJlIGNvbW11bml0eSwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgcmF0aW8gb2YgdGhlIHNlcXVlbmNlcy4gVGhpcyBjYW4gZ2l2ZSB1cyBpbmZvcm1hdGlvbnMgb24gdGhlIGludGVyIGluZGl2aWR1YWwgZGlzcGVyc2lvbiA6IHRoZSBoaWdoZXIgdGhlIGludHJhLXNwZWNpZXMgZGlzcGVyc2lvbiwgdGhlIGxvd2VyIHRoZSBzaXplIG9mIHRoZSBjb3JlIGFuZCB0aGUgbGFyZ2VyIHRoZSB2YXJpYWJsZSBiYWN0ZXJpYWwgY29tbXVuaXR5IG9mIHRoZSBjb21wYXJ0bWVudCBvciBzcGVjaWVzLiAKCmBgYHtyIFJhdGlvIEFTViBlbnRlcmljIENvcmUvIEFTViBpbml0aWFsICwgZWNobz0gVCwgZXZhbD0gVCAsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ICJjZW50ZXIifQpyYXRpb19ndXQgPC0gc3VtKHNhbXBsZV9zdW1zKHNleV9ndXRfY29yZSkpIC8gc3VtKHNhbXBsZV9zdW1zKHNleXJmZl9ndXQpKQpwZXJjZW50KHJhdGlvX2d1dCkKYGBgCgojIyMjIEl0b2wKCkluIG9yZGVyIHRvIHJlcHJlc2VudCB0aGUgdGF4YSBpbiB0aGUgd2hvbGUgbWljcm9iaWFsIGRlc2NyaXB0aW9uIHZpYSBCbGFzdCwgd2UgY2FuIHRoZW4gcmVwcmVzZW50IHRoZSBzb3VyY2Ugb2Ygb3VyIHNlcXVlbmNlICh3aGVyZSB0aGV5IGhhdmUgYWxyZWFkeSBiZWVuIGRlc2NyaWJlZCkgaW4gYW4gaW50ZXJhY3RpdmUgdHJlZSBpbiBbSXRvbF0oaHR0cHM6Ly9pdG9sLmVtYmwuZGUvKSAoSW50ZXJhY3RpdmUgVHJlZSBvZiBMaWZlKS4gVG8gZG8gdGhhdCwgd2UgbmVlZCB0byB0cmFuc2Zvcm0gb3VyIHBoeWxvZ2VuZXRpYyB0cmVlIGZyb20gdGhlIHBoeWxvc2VxIG9iamVjdCAob2J0YWluZWQgYWZ0ZXIgYW4gYWxpZ25lbWVudCBpbiBBUkIgaGVyZSkgaW4gYW4geG1sIG91dHB1dCB0aGFua3MgdG8gdGhlIGB3cml0ZV94bWwoKWAgZnVuY3Rpb24uIAoKYGBge3IgdG8gaW5zZXJ0IGFuIHRyZWUsIGV2YWwgPSBGICwgZWNobz0gVCAsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJVU0NCaW9zdGF0cy9ycGh5bG94bWwiKQpsaWJyYXJ5KGFwZSkKbGlicmFyeShycGh5bG94bWwpCnNldC5zZWVkKDEyKQpndXRfdHJlZSA8LSBzZXlfZ3V0X2NvcmVAcGh5X3RyZWUKZ3V0X3BoeWxveG1sIDwtIHdyaXRlX3BoeWxveG1sKGd1dF90cmVlKQpjYXQoYXMuY2hhcmFjdGVyKGd1dF9waHlsb3htbCkpCnhtbDI6OndyaXRlX3htbChndXRfcGh5bG94bWwsICJndXRfcGh5bG94bWwueG1sIikKYGBgCgpUaGVuLCBpbiBvcmRlciB0byBhZGQgc3VwcGxlbWVudGFyeSBlbnZkYXRhIChvdGhlciB0aGFuIEJsYXN0LCBhcyBhIGdyYWRpZW50LCBob3N0IHNwZWNpZXMsIGdlb2dyYXBoeSBldGMuLi4uKSB5b3UgaGF2ZSB0byB1c2UgYSBzcGVjaWFsIHRlbXBsYXRlIC50eHQgZm9yIEl0b2wuIFRoZSBmdW5jdGlvbiBgY3JlYXRlX2l0b2xfZmlsZXMoZW52Lnhsc3gpYCBmcm9tIHRoZSBzY3JpcHQgW3RhYmxlMml0b2wuUl0oaHR0cHM6Ly9naXRodWIuY29tL21nb2VrZXIvdGFibGUyaXRvbC9ibG9iL21hc3Rlci90YWJsZTJpdG9sLlIpIGlzIHZlcnkgdXNlZnVsIHRvIG1hZGUgYXV0b21hdGljYWxseSB0aGUgdGVtcGxhdGVzIGZyb20geW91ciBlbnYgZmlsZS4gWW91IGFyZSBmcmVlIHRvIGNoYW5nZSB0aGUgY29sb3JzIGFuZCBzaGFwZSBhcyB5b3Ugd2FudCBuZXh0LiBJdCBmYXN0ZXIgdGhhbiBtYWRlIGEgbWFudWFsbHkgZW50cnkgaW4gdGhlIEl0b2wgd2Vic2l0ZS4gCgoqKioKCiMjIyBQYXJ0IElWYjogQWxnYWwgY29yZSBtaWNyb2Jpb21lCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKV2UgY3JlYXRlIGEgbmV3IGZvbGRlciBmb3IgdGhlIGFsZ2FsIG1pY3JvYmlvbWUgYW5kIGRldGVybWluZSB0aGUgY29yZS4KCmBgYHtyIGFsZ2FsIGNvcmUgd2QsIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9BbGdhZS9Db3JlLyIpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFQpCmxvYWQocGFzdGUwKGRpcl90YXhhX2Fzc2lnbiwgInNleV9hbGdhZS5SRGF0YSIpKQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlyZmZfYWxnYWUuUkRhdGEiKSkKYGBgCgojIyMjIENvcmUgZGV0ZXJtaW5hdGlvbgoKYGBge3IgYWxnYWwgY29yZSBkZXRlcm1pbmF0aW9uLCBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmc9RiwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkobGFiZHN2KQpvdHVfdGFibGUgPC0gc2V5cmZmX2FsZ2FlQG90dV90YWJsZUAuRGF0YQphYnVvY2NwbG90X290dSA8LSBhYnVvY2Mob3R1X3RhYmxlKQojc3ViX29iamVjdHMgb2YgYWJ1b2NjIG9iamVjdHMKc3RyKGFidW9jY3Bsb3Rfb3R1KQojIHRyYW5zZm9ybSBzcGMucGx0IHZlY3RvciBpbnRvIHRhYmxlIGluIG9yZGVyIHRvIGNhbGN1bGF0ZSBzcGVjaWZpYyByaWNobmVzcwpyaWNobmVzc19vdHUgPC0gZGF0YS5mcmFtZShhYnVvY2NwbG90X290dSRzcGMucGx0KQojIG9jY3VyZW5jZSBvZiBlYWNoIE9UVQpvdHVfb2NjdXJlbmNlIDwtIGRhdGEuZnJhbWUoYWJ1b2NjcGxvdF9vdHUkcGx0LnNwYykKbWVhbi5hYnVuX290dSA8LSBjb2xTdW1zKG90dV90YWJsZSkvb3R1X29jY3VyZW5jZQpzcXVhcmVfb3R1IDwtIG90dV90YWJsZV4yCnNzX290dSA8LSBkYXRhLmZyYW1lKGNvbFN1bXMoc3F1YXJlX290dSkpCiMgVmFyaWFuY2UgY2FsY3VsYXRpb24KdmFyaWFuY2Vfb3R1PXNzX290dS9vdHVfb2NjdXJlbmNlLW1lYW4uYWJ1bl9vdHVeMgpkaXNwX290dSA8LSAodmFyaWFuY2Vfb3R1L21lYW4uYWJ1bl9vdHUpKm90dV9vY2N1cmVuY2UKIyBJQyBjYWxjdWxhdGlvbiBmb3IgUG9pc3NvbiBkaXN0cmlidXRpb24gdXNpbmcgQ2hpIHNxdWFyZSBkaXN0cmlidXRpb24gKHZhbHVlIGFuZCBmb3JtdWxhIHdpdGhpbiBaYXIgcDU3NCkKbGlicmFyeShlcGl0b29scykKcG9pc2ljX290dSA9IHBvaXMuZXhhY3Qob3R1X29jY3VyZW5jZSwgY29uZi5sZXZlbCA9IDAuOTUpCmFsZ2FlX2RzdGF0X290dSA8LSBjYmluZChtZWFuLmFidW5fb3R1LCBkaXNwX290dSwgb3R1X29jY3VyZW5jZSwgcG9pc2ljX290dSkKbmFtZXMoYWxnYWVfZHN0YXRfb3R1KSA8LSBjKCJhdmVyYWdlIiwiZGlzcCIsICJvY2N1cmVuY2UiLCAieCIsICJwdCIsICJyYXRlIiwgImxvd2VyIiwgInVwcGVyIiwgInByb2IiKQpzYXZlKGFsZ2FlX2RzdGF0X290dSwgZmlsZT1wYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJhbGdhZV9zZXlfZHN0YXRfYXN2LlJEYXRhIikpCiMgU2VsZWN0aW9uIG9mIGNvcmUgQVNWcwphbGdhZV9zZXlfY29yZV9vdHUgPC0gYWxnYWVfZHN0YXRfb3R1W2FsZ2FlX2RzdGF0X290dSRkaXNwID4gYWxnYWVfZHN0YXRfb3R1JHVwcGVyLF0KYWxnYWVfc2V5X2NvcmVfb3R1IDwtIG5hLmV4Y2x1ZGUoYWxnYWVfc2V5X2NvcmVfb3R1KQphbGdhZV90YXggPC0gZGF0YS5mcmFtZShzZXlyZmZfYWxnYWVAdGF4X3RhYmxlQC5EYXRhKQphbGdhZV9zZXlfY29yZV9vdHUkdGF4IDwtIGFsZ2FlX3RheFtyb3duYW1lcyhhbGdhZV90YXgpICVpbiUgcm93Lm5hbWVzKGFsZ2FlX3NleV9jb3JlX290dSksNl0KYWxnYWVfc2V5X2NvcmVfb3R1JHBoeWx1bSA8LSBhbGdhZV90YXhbcm93bmFtZXMoYWxnYWVfdGF4KSAlaW4lIHJvdy5uYW1lcyhhbGdhZV9zZXlfY29yZV9vdHUpLDJdCnNhdmUoYWxnYWVfc2V5X2NvcmVfb3R1LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCJhbGdhZV9zZXlfY29yZV9vdHUuUmRhdGEiKSkKCnNleV9hbGdhZV9jb3JlIDwtcHJ1bmVfdGF4YShyb3duYW1lcyhhbGdhZV9zZXlfY29yZV9vdHUpLCBzZXlyZmZfYWxnYWUpCnNhdmUoc2V5X2FsZ2FlX2NvcmUsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzZXlfYWxnYWVfY29yZS5SRGF0YSIpKQpgYGAKClRvIGJsYXN0IHRoZSByZWFkcyBvZiB0aGUgY29yZSwgd2UgbmVlZCB0byBnZW5lcmF0ZSBhIGZhc3RhIGZpbGUgd2l0aCB0aGUgZnVuY3Rpb24gYHdyaXRlWFN0cmluZ1NldCgpYC4KCmBgYHtyIGZhc3RhIGFsZ2FsIGZpbGUsIGVjaG8gPSBGLCBldmFsID0gRiwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KYWxnYWVfbmFtZXMgPC0gY29sbmFtZXMoc2V5X2FsZ2FlX2NvcmVAb3R1X3RhYmxlKQphbGdhZV90cmVlIDwtIHN1YnNldF90YXhhKHNleV9hbGdhZV9jb3JlLCByb3duYW1lcyhzZXlfYWxnYWVfY29yZUB0YXhfdGFibGUpICVpbiUgYWxnYWVfbmFtZXMpCmFsZ2FlX3RyZWUKQmlvc3RyaW5nczo6d3JpdGVYU3RyaW5nU2V0KHNleV9hbGdhZV9jb3JlQHJlZnNlcSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywic2V5X2FsZ2FlX2NvcmUuZmFzdGEiKSkKYGBgCgojIyMjIENvbXBvc2l0aW9uIG9mIHRoZSBjb3JlCgpgYGB7ciBhbGdhbCBjb21wb3NpdGlvbiBzdGFja3Bsb3QsIGVjaG8gPSBGLCBldmFsID0gVCwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0KbGlicmFyeShkcGx5cikKYWxnYWVfY29yZV9vcmRlciA8LSBzZXlfYWxnYWVfY29yZSAlPiUKICB0YXhfZ2xvbSh0YXhyYW5rID0gIk9yZGVyIikgJT4lICAgICAgICAgICAgICAgICAgICAgIyBhZ2dsb21lcmF0ZSBhdCBwaHlsdW0gbGV2ZWwKICB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhmdW5jdGlvbih4KSB7eC9zdW0oeCl9ICkgJT4lICMgVHJhbnNmb3JtIHRvIHJlbC4gYWJ1bmRhbmNlCiAgcHNtZWx0KCkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE1lbHQgdG8gbG9uZyBmb3JtYXQKICBmaWx0ZXIoQWJ1bmRhbmNlID4gMC4wMikgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICMgRmlsdGVyIG91dCBsb3cgYWJ1bmRhbmNlIHRheGEKICBhcnJhbmdlKE9yZGVyKSAgICAgIAoKc2F2ZShhbGdhZV9jb3JlX29yZGVyICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImFsZ2FlX2NvcmVfb3JkZXIuUkRhdGEiKSkKYGBgCgoKUGxvdCBhIHRyZWVtYXAgb2YgdGhlIGNvcmUgdGhhbmtzIHRvIHRoZSBgdHJlZW1hcCgpYCBmdW5jdGlvbiBmb3IgdGhlIG1haW4gY29udHJpYnV0b3Igb2YgdGhlIGNvcmUuIApgYGB7ciB0cmVlbWFwIG9mIHRoZSBjb3JlIGVwaXBoeXRlLCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciIgfQphbGdhZV9jb3JlX29yZGVyJFBoeWx1bSA9IGFzLmNoYXJhY3RlcihhbGdhZV9jb3JlX29yZGVyJFBoeWx1bSkgIyBBdm9pZCBlcnJvciBtZXNzYWdlIHdpdGggZmFjdG9yIGZvciBuZXh0IHN0ZXAKc29ydCh0YWJsZShmYWN0b3IoYWxnYWVfY29yZV9vcmRlciRQaHlsdW0pKSwgVCkKYWxnYWVfY29yZV9vcmRlclshYWxnYWVfY29yZV9vcmRlciRQaHlsdW0gJWluJSAKICAgICAgICAgICAgICAgICAgIGMoIlByb3Rlb2JhY3RlcmlhIiwgIkJhY3Rlcm9pZGV0ZXMiLCJDeWFub2JhY3RlcmlhIiwiVmVycnVjb21pY3JvYmlhIiwiUGxhbmN0b215Y2V0ZXMiKSx3aGljaChuYW1lcyhhbGdhZV9jb3JlX29yZGVyKSA9PSAiUGh5bHVtIiwgVCldIDwtICJPdGhlciIgI0NoYW5nZSBwaHlsdW0gdG8gb3RoZXIgZm9yIHRob3NlIG5vdCBpbmNsdWRlZCBpbiB0aGUgbGlzdAoKZ3JvdXAgPC0gIGFsZ2FlX2NvcmVfb3JkZXIkUGh5bHVtCnN1Ymdyb3VwIDwtIGFsZ2FlX2NvcmVfb3JkZXIkT3JkZXIKdmFsdWUgPC0gYWxnYWVfY29yZV9vcmRlciRBYnVuZGFuY2UKCmFsZ2FlX2NvcmVfdHJlZW1hcF9kYXRhPWRhdGEuZnJhbWUoZ3JvdXAsc3ViZ3JvdXAsdmFsdWUpCgpsaWJyYXJ5KHRyZWVtYXApCmFsZ2FlX2NvcmVfdHJlZW1hcCA8LSB0cmVlbWFwKGFsZ2FlX2NvcmVfdHJlZW1hcF9kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXg9YygiZ3JvdXAiLCJzdWJncm91cCIpLCB2U2l6ZSA9ICJ2YWx1ZSIsIHR5cGUgPSAiaW5kZXgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGNvbG9yLmxhYmVscz1jKCJ3aGl0ZSIsImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250c2l6ZS5sYWJlbHM9YygxMiksYmcubGFiZWxzPWMoInRyYW5zcGFyZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZS5sYWJlbHM9YygyLDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9yZGVyLmNvbD1jKCJibGFjayIsIndoaXRlIiksIGJvcmRlci5sd2RzPWMoNCwyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbi5sYWJlbHM9bGlzdChjKCJjZW50ZXIiLCAiY2VudGVyIiksYygibGVmdCIsICJib3R0b20iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iU2V5Y2hlbGxlcyBBbGdhZSBDb3JlIFRyZWVtYXAiLGZvbnRzaXplLnRpdGxlPTEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhbWlseS50aXRsZSA9InNlcmlmIikKCmBgYAoKYW5kIHZpc3VhbGl6ZSB0aGUgcmVsYXRpdmUgY29udHJpYnV0aW9uIG9mIHRoZSBkaWZmZXJlbnQgdGF4YSAod2l0aCB0aGUgYGZpbGw9YCBhcmd1bWVudCBmb3IgdGhlIGxldmVsIG9mIHRoZSB0YXhvbm9teSB5b3Ugd2FudCByZXByZXNlbnQpIGZvciB0aGUgZGlmZmVyZW50IHJlZWYgY29uZGl0aW9uIG9yIHNpdGUgd2l0aCB0aGUgYXJndW1lbnQgYHg9YC4KCipFeCogOiBUaGUgY29tcG9zaXRpb24gb2YgdGhlIGNvcmUgYWxnYWwgbWljcm9iaW9tZSBiZXR3ZWVuIE1haGUgYW5kIFByYXNsaW4gYXQgcGh5bHVtIGxldmVsLiAKCmBgYHtyIHN0YWNrZWRwbG90IGYgdGhlIGNvcmUgZXBpcGh5dGUsIGVjaG89IEYsIGV2YWw9IFQgLCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSAiY2VudGVyIiB9CmFsZ2FlX2NvcmVfb3JkZXIkUGh5bHVtIDwtIHN0cl9yZXBsYWNlX2FsbChhbGdhZV9jb3JlX29yZGVyJFBoeWx1bSxjKCJPdGhlciIgPSAiWi1PdGhlciIpKQoKZ2dwbG90KGFsZ2FlX2NvcmVfb3JkZXIsIGFlcyh4ID0gc2l0ZSwgeSA9IEFidW5kYW5jZSwgZmlsbCA9IFBoeWx1bSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIpICsgCiAgeWxhYigiUmVsYXRpdmUgQWJ1bmRhbmNlIChPcmRlciA+IDIlKSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArICNyZW1vdmUgdGhlIHNwYWNlIGJlbG93IHRoZSAwIG9mIHRoZSB5IGF4aXMgaW4gdGhlIGdyYXBoCiAgZ2d0aXRsZSgiUGh5bHVtIENvbXBvc2l0aW9uIG9mIEFsZ2FlIGJldHdlZW4gc2l0ZXMiKSArCiAgeGxhYigiU2l0ZSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBoeWx1bV9jb2xvcnMpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDApLCAKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtYWpvci1ncmlkIGxhYmVscwogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTUpLCAKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiwgc2l6ZSA9IDEzKSwgCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLCBzaXplID0gMTUpLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsICBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFtaWx5ID0gInNlcmlmIikpCmBgYAoKIyMjIyBDb3JlIHJhdGlvCgpUbyBoYXZlIGEgcmVwcmVzZW50YXRpb24gb2YgdGhlIHNpemUgb2YgdGhlIGNvcmUgaW4gdGhlIGVudGlyZSBjb21tdW5pdHksIHdlIGNhbiBjYWxjdWxhdGUgdGhlIHJhdGlvIG9mIHRoZSBzZXF1ZW5jZXMuIFRoaXMgY2FuIGdpdmUgdXMgaW5mb3JtYXRpb25zIG9uIHRoZSBpbnRlciBpbmRpdmlkdWFsIGRpc3BlcnNpb24gOiB0aGUgaGlnaGVyIHRoZSBpbnRyYS1zcGVjaWVzIGRpc3BlcnNpb24sIHRoZSBsb3dlciB0aGUgc2l6ZSBvZiB0aGUgY29yZSBhbmQgdGhlIGxhcmdlciB0aGUgdmFyaWFibGUgYmFjdGVyaWFsIGNvbW11bml0eSBvZiB0aGUgY29tcGFydG1lbnQgb3Igc3BlY2llcy4gCgpgYGB7ciBSYXRpbyBBU1YgQ29yZS8gQVNWIGluaXRpYWwgLCBlY2hvPSBULCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciJ9CnJhdGlvX2FsZ2FlIDwtIHN1bShzYW1wbGVfc3VtcyhzZXlfYWxnYWVfY29yZSkpIC8gc3VtKHNhbXBsZV9zdW1zKHNleXJmZl9hbGdhZSkpCnBlcmNlbnQocmF0aW9fYWxnYWUpCmBgYAoqKioKCiMjIyBQYXJ0IElWYzogR2xvYmFsIGNvcmUgYW5kIGNvbXBhcmlzb24KW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpXZSBjcmVhdGUgYSBuZXcgZm9sZGVyIGZvciB0aGUgdG90YWwgY29yZSBtaWNyb2Jpb21lIGFuZCBjb21wYXJlIGJvdGggY29tcGF0bWVudCBpbiBjb21wb3NpdGlvbiAoTGVmU2UpIGFuZCBpbiBkaXZlcnNpdHkgKGFscGhhIGFuZCBiZXRhKS4KCgpgYGB7ciB0b3RhbCBjb3JlIHdkLCBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmc9RiwgbWVzc2FnZSA9IEZ9CmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvVG90YWwgQ29yZS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQpsb2FkKHBhc3RlMChkaXJfdGF4YV9hc3NpZ24sICJzZXlfZmluYWwuUkRhdGEiKSkKbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5cmZmX2ZpbmFsLlJEYXRhIikpCmBgYAoKV2UgdXNlIHRoZSBvdHUgdGFibGVzIG9mIHRoZSBlbnRlcmljIGNvcmUgYW5kIGFsZ2FsIGNvcmUgdG8ga2VlcCB0aGUgQVNWcyBuYW1lcyBhbmQgc3Vic2V0IHRoZW0gaW4gdGhlIGluaXRpYWwgcGh5bG9zZXEgb2JqZWN0IGBzZXlfZmluYWxgLgoKYGBge3IgZ2xvYmFsIGNvcmUgY3JlYXRpb24gLGVjaG89IFQsIGV2YWw9IFQgLCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgfQpjb3JlX0FTViA8LSB1bmlxdWUoYyhyb3cubmFtZXMoZ3V0X3NleV9jb3JlX290dSksIHJvdy5uYW1lcyhhbGdhZV9zZXlfY29yZV9vdHUpKSkKZ2xvYmFsX2NvcmUgPC0gc3Vic2V0X3RheGEoc2V5X2ZpbmFsLCB0YXhhX25hbWVzKHNleV9maW5hbCkgJWluJSBjb3JlX0FTVikKc2F2ZShnbG9iYWxfY29yZSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImdsb2JhbF9jb3JlLlJEYXRhIikpCgpjb3JlX3BoeXNlcV9vcmRlciA8LSBnbG9iYWxfY29yZSAlPiUKICB0YXhfZ2xvbSh0YXhyYW5rID0gIk9yZGVyIikgJT4lICAgICAgICAgICAgICAgICAgICAgIyBhZ2dsb21lcmF0ZSBhdCBvcmRlciBsZXZlbAogIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGZ1bmN0aW9uKHgpIHt4L3N1bSh4KX0gKSAlPiUgIyBUcmFuc2Zvcm0gdG8gcmVsLiBhYnVuZGFuY2UKICBwc21lbHQoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTWVsdCB0byBsb25nIGZvcm1hdAogIGFycmFuZ2UoT3JkZXIpCnNhdmUoY29yZV9waHlzZXFfb3JkZXIgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9waHlzZXFfb3JkZXIuUkRhdGEiKSkKYGBgCgoKTm93IHdlIGNhbiB2aXN1YWxpemUgZWFzaWx5IGJ5IGNvbXBhcnRtZW50cyB0aGUgYmFjdGVyaWFsIGNvbXBvc2l0aW9uIHdpdGggdGhlIGNob3NlbiB0YXhhIGxldmVscyAoZS5nLiBQaHlsdW0gaGVyZSkuIAoKYGBge3Igc3RhY2tlZCBwbG90IG9mIHRoZSBnbG9iYWwgY29yZSxlY2hvPSBGLCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciIgfQpjb3JlX3BoeXNlcV9vcmRlciRsaW5lYWdlIDwtIHN0cl9yZXBsYWNlX2FsbChjb3JlX3BoeXNlcV9vcmRlciRsaW5lYWdlLCBjKCJwbGFudGFlIiA9ICJBbGdhZSIsICJ2ZXJ0ZWJyYXRlIj0iR3V0IikpCgpnZ3Bsb3QoY29yZV9waHlzZXFfb3JkZXIsIGFlcyh4ID0gbGluZWFnZSAsIHkgPSBBYnVuZGFuY2UsIGZpbGwgPSBQaHlsdW0pKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBoeWx1bV9jb2xvcnMpICsKICB5bGFiKCJSZWxhdGl2ZSBBYnVuZGFuY2UgKFBoeWx1bSA+IDIlKSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArICNyZW1vdmUgdGhlIHNwYWNlIGJlbG93IHRoZSAwIG9mIHRoZSB5IGF4aXMgaW4gdGhlIGdyYXBoCiAgZ2d0aXRsZSgiQ29yZSBQaHlsdW0gQ29tcG9zaXRpb24gYmV0d2VlbiBHdXQgYW5kIEFsZ2FlIikgKwogIHRoZW1lX2J3KCkgKwogIHhsYWIoIkZhbWlseSIpKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSAgKyAKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDApLCAKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDE1KSwgCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFtaWx5ID0gInNlcmlmIiwgYW5nbGUgPSAwKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiwgc2l6ZSA9IDEzKSwgCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLCBzaXplID0gMTUpLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsICBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFtaWx5ID0gInNlcmlmIikpCmBgYAoKIyMjIyBBbHBoYSBkaXZlcnNpdHkgY29tcGFyaXNvbnMKCldlIGNvbXBhcmUgdGhlIHRheG9ub21pYyBkaXZlcnNpdHkgKG9ic2VydmVkIHJpY2huZXNzIGFuZCBleHAoc2hhbm5vbiBpbmRleCkgZm9yIHRoZSBlZmZlY3RpdmUgbnVtYmVyIG9mIHNwZWNpZXMgKEVOUykpIGJldHdlZW4gdGhlIG5vcm1hbGl6ZWQgdGFibGVzICg0NzggQVNWcyBub3JtYWxpemVkKSBvZiB0aGUgZW50ZXJpYyBtaWNyb2Jpb21lIGFuZCBlcGlwaHl0ZXMgYmFjdGVyaWEuIE5vdGUgdGhhdCA0Nzggd2FzIGNob3NlbiBiZWNhdXNlIExldGhyaW51cyBzYW1wbGVzIHdlcmUgdmVyeSBwb29yIGJ1dCBlc3NlbnRpYWwgZm9yIHRoZSBjb21wYXJpc29ucyBiZXR3ZWVuIGhlYWx0aCBzdGF0dXMgb2YgdGhlIHJlZWYuIEZvbGxvd2luZyB0aGUgcmljaG5lc3MgY3VydmVzIG1hZGUgaGlnaGVyIGR1cmluZyB0aGUgW1BoeWxvc2VxIHByb2Nlc3NdKCNQYXJ0IElJOiBQaHlsb3NlcSBwcm9jZXNzKQoKYGBge3IgZ2xvYmFsIGFscGhhIGRpdmVyc2l0eSxlY2hvPSBGLCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciIgIH0KYm94MSA9IHBsb3RfcmljaG5lc3Moc2V5cmZmX2ZpbmFsICwgbWVhc3VyZXMgPSBjKCJPYnNlcnZlZCIsIlNoYW5ub24iKSAsIGNvbG9yID0gImxpbmVhZ2UiKQpib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlID0gZXhwKGJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUpCmxldmVscyhib3gxJGRhdGEkdmFyaWFibGUpPC0gYygiUmljaG5lc3Mgb2JzZXJ2ZWQiLCAiU2hhbm5vbiAoRU5TKSIpCmJveDEkZGF0YSRsaW5lYWdlIDwtIHN0cl9yZXBsYWNlX2FsbChib3gxJGRhdGEkbGluZWFnZSwgYygicGxhbnRhZSIgPSAiQWxnYWUiLCAidmVydGVicmF0ZSI9Ikd1dCIpKQoKbGlicmFyeShnZ3NpZ25pZikKCnBhbGV0dGUgPSBjKCJkYXJrZ3JlZW4iICwgImRhcmtvcmFuZ2UiKQoKc2V5X2ZpbmFsX2FscGhhX2RpdiA9ICBnZ3Bsb3QoYm94MSRkYXRhLCBhZXMoeCA9IGxpbmVhZ2UgLCB5ID0gdmFsdWUsIGNvbG9yID0gbGluZWFnZSkpICsKICBnZW9tX2ppdHRlcihwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4yMCksIGFscGhhID0gMC41LCBzaXplID0gMykgKyB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTE4LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDE4LCBhbmdsZSA9IDApLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyAKICBmYWNldF93cmFwKCB+IHZhcmlhYmxlLCBucm93PTEsIG5jb2w9NSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoIkFsZ2FlIiwgIkd1dCIpKSwgCiAgICAgICAgICAgICAgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRleHRzaXplPTYsIGNvbG9yPSJibGFjayIsIGZhbWlseSA9ICJzZXJpZiIsIHZqdXN0ID0gMC41KQpzZXlfZmluYWxfYWxwaGFfZGl2CgpsaWJyYXJ5KHBnaXJtZXNzKQpNVy5yaWNobmVzcyA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGUgPT0iUmljaG5lc3Mgb2JzZXJ2ZWQiXSB+IGJveDEkZGF0YSRsaW5lYWdlW2JveDEkZGF0YSR2YXJpYWJsZT09IlJpY2huZXNzIG9ic2VydmVkIl0sIG1ldGhvZCA9ICJib25mZXJyb25pIikKTVcucmljaG5lc3MgPSBjYmluZChNVy5yaWNobmVzcyRzdGF0aXN0aWMgLCBNVy5yaWNobmVzcyRwLnZhbHVlKQpNVy5zaGFubm9uID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSB+IGJveDEkZGF0YSRsaW5lYWdlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSwgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpNVy5zaGFubm9uID0gY2JpbmQoTVcuc2hhbm5vbiRzdGF0aXN0aWMgLCBNVy5zaGFubm9uJHAudmFsdWUpCiMgUGxvdCB0aGUgcmVzdWx0cyAgCk1XLnRlc3QgPC0gcmJpbmQoTVcucmljaG5lc3MsIE1XLnNoYW5ub24pCnJvd25hbWVzKE1XLnRlc3QpID0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKY29sbmFtZXMoTVcudGVzdCkgPSBjKCdXIHN0YXQnICwgJ3AtdmFsdWUnKQpNVy50ZXN0CmBgYAoKIyMjIyBCZXRhIGRpdmVyc2l0eSBjb21wYXJpc29ucwoKRXZlbiB3ZSB3b3JrIG9uIHRoZSBjb3JlIG9mIG5vcm1hbGl6ZWQgdGFibGVzLCB3ZSBjYWxjdWxhdGUgdGhlIGJldGEgZGl2ZXJzaXR5IG9udCB0aGUgcmVsYXRpdmUgQVNWcyBjb3VudHMgd2l0aCB0aGUgQnJheS1jdXJ0aXMgZGlzdGFuY2VzIHdpdGggYHZlZ2Rpc3RgIGZ1bmN0aW9uIGZyb20gW3ZlZ2FuIHBhY2thZ2UgKE9rc2FuZW4gZXQgYWwuLCAyMDE5KV0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT12ZWdhbikuCgpgYGB7ciBnbG9iYWwgYmV0YSBkaXZlcnNpdHksZWNobz0gRiwgZXZhbD0gVCAsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ICJjZW50ZXIiIH0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9Ub3RhbCBDb3JlLyIpCmxvYWQocGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiZ2xvYmFsX2NvcmUuUkRhdGEiKSkKZ2xvYmFsX2NvcmVfcmVsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGdsb2JhbF9jb3JlLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpICkKc2F2ZShnbG9iYWxfY29yZV9yZWwsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJnbG9iYWxfY29yZV9yZWwuUkRhdGEiKSkKIyBQQ09BIGNvZGEgJiBQZXJtYW5vdmEKbGlicmFyeSh2ZWdhbikKb3R1IDwtIHZlZ2Rpc3QoZ2xvYmFsX2NvcmVfcmVsQG90dV90YWJsZSwgbWV0aG9kID0gImJyYXkiKQpzYXZlKG90dSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImJldGFfbWF0cmljZXMuUkRhdGEiKSkKcGNvYS5zdWIgPC0gcGNvYShvdHUpCnBjb2FfY29vcmQgPC0gcGNvYS5zdWIkdmVjdG9yc1ssMTozXQpzYXZlKHBjb2Euc3ViLHBjb2FfY29vcmQgLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJwY29hLnZhbHVlcy5SRGF0YSIpKQoKIyBDb250cnVjdGlvbiBvZiB0aGUgdGFibGUgZm9yIGdyYXBoaWMgCmxpYnJhcnkoc3RyaW5ncikKc2FtcF9kYXRhIDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEoZ2xvYmFsX2NvcmVfcmVsKSkKbmFtZXMoc2FtcF9kYXRhKVs2XSA9ICJUeXBlIgpodWxsIDwtIGNiaW5kKHBjb2FfY29vcmQsIHNhbXBfZGF0YSkKaHVsbCRUeXBlIDwtIHN0cl9yZXBsYWNlX2FsbChodWxsJFR5cGUsIGMoInBsYW50YWUiID0gIkFsZ2FlIiwgInZlcnRlYnJhdGUiPSJHdXQiKSkKCiMgV2hhdCBpcyB0aGUgcGVyY2VudGFnZSBvZiB0aGUgZXhwbGljYXRpdmUgdmFyaWFuY2U/IApwYXN0ZSgiQXhpcyAxIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSkpICMgOC42ICUKcGFzdGUoIkF4aXMgMiA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0pKSAjIDYuNiAlCnBhc3RlKCJBeGlzIDMgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzNdKSkgIyA1LjEgJQpwYXN0ZSgiQXhpcyA0IDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1s0XSkpICMgNC45ICUKcGFsZXR0ZSA9IGMoImRhcmtncmVlbiIsICJkYXJrb3JhbmdlIikKCiMgUGxvdApwY29hLmJyYXkgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gaHVsbCwgYWVzKHg9QXhpcy4xLCB5PUF4aXMuMiwgY29sb3IgPSBUeXBlKSwgYWxwaGEgPSAwLjcsIHNpemUgPSA1LCBzaGFwZSA9IDE2KSArCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB5LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xOCwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xOCwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtYWpvci1ncmlkIGxhYmVscwogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1pbm9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiwgc2l6ZSA9IDE2KSwgCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDAsZmFtaWx5ID0gInNlcmlmIikpKwogIGxhYnMoY29sb3VyID0gIlR5cGUiLCBmaWxsID0gIlR5cGUiKQoKcGNvYS5icmF5CmBgYAoKV2UgdGhlbiBjb21wYXJlIHRoZSBiZXRhIGRpdmVyc2l0eSB3aXRoIHRoZSBgYWRvbmlzYCBmdW5jdGlvbiBhbmQgdGVzdCB0aGUgZGlzcGVyc2lvbiBiZXR3ZWVuIHNhbXBsZXMgd2l0aCBgYmV0YWRpc3BlcmAuIAoKYGBge3IgUGVybWFub3ZhIGFuZCBCZXRhZGlzcGVyLCBlY2hvPSBULCBldmFsPSBUICwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciJ9CmxpYnJhcnkocGFpcndpc2VBZG9uaXMpCmFkb25pcyhvdHUgfiBUeXBlLCBkYXRhID0gc2FtcF9kYXRhKSAjIGJldHdlZW4gZ3V0LCBtYWNyb2FsZ2FlIGFuZCB0dXJmCnBhaXJ3aXNlLmFkb25pcyhvdHUgLCBzYW1wX2RhdGEkVHlwZSkKCmJldGEgPC0gYmV0YWRpc3BlcihvdHUsIHNhbXBfZGF0YSRUeXBlKQpwZXJtdXRlc3QoYmV0YSkKYGBgCgojIyMjIExFZlNlIG9uIGNvbXBhcnRtZW50cwoKSW4gb3JkZXIgdG8gZGV0ZWN0IGJpb21hcmtlcnMgcHJvcGVyIHRvIGVhY2ggY29tcGFydG1lbnQsIHdlIHByb2NlZWQgdG8gYSBbTGluZWFyIGRpc2NyaW1pbmFudCBhbmFseXNpcyBvbiBlZmZlY3Qgc2l6ZSAoTEVmU2UpIGF2YWlsYWJsZSBvbiBHYWxheHldKGh0dHBzOi8vZ2FsYXh5cHJvamVjdC5vcmcvbGVhcm4vdmlzdWFsaXphdGlvbi9jdXN0b20vbGVmc2UvKS4gSGVyZSBpcyB0aGUgY29kZSB0byBwcmVwYXJlIHRoZSBkYXRhIGlucHV0IHRvIHByb2NlZWQgaW4gR2FsYXh5IGh1Yi4gCgpgYGB7ciBMREEgd2QsIGVjaG89IEYsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL1RvdGFsIENvcmUvTERBLyIpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFQpCmBgYAoKYGBge3IgTEVmU2UgcHJlcGFyYXRpb24gZGF0YSwgZWNobz0gRiwgZXZhbD0gRiwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CnNleV9jb21wYXJ0bWVudC5nZW51cyA8LSB0YXhfZ2xvbShnbG9iYWxfY29yZSwgIkdlbnVzIiwgTkFybSA9IFRSVUUpICNtZXJnZXMgc3BlY2llcyB0aGF0IGhhdmUgdGhlIHNhbWUgR2VudXMgKyBmaWx0cmUgR2VucmVzIE5BCnNhdmUoc2V5X2NvbXBhcnRtZW50LmdlbnVzLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2V5X2NvbXBhcnRtZW50LmdlbnVzLlJEYXRhIikpIAp0YXhvID0gZGF0YS5mcmFtZSh0YXhfdGFibGUoc2V5X2NvbXBhcnRtZW50LmdlbnVzKSkKdGF4X25hbWUgPC0gcGFzdGUodGF4byREb21haW4sIHRheG8kUGh5bHVtLCB0YXhvJENsYXNzLCB0YXhvJE9yZGVyLCB0YXhvJEZhbWlseSwgdGF4byRHZW51cywgIHNlcD0ifCIpCnRheF9uYW1lMiA8LSBjKCJUeXBlIix0YXhfbmFtZSkKc2F2ZSh0YXhvLCB0YXhfbmFtZTIsIGZpbGU9cGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nICwgInNleV9jb21wYXJ0bWVudC5nZW51c190YXhvLlJEYXRhIikpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKHNleV9jb21wYXJ0bWVudC5nZW51cykpCmxldmVscyhzYW1wX2RhdGEkbGluZWFnZSkgPC0gYygiQWxnYWUiLCAiR3V0IikKdHlwZV9sZWZzZSA8LSBkYXRhLmZyYW1lKHNhbXBfZGF0YVssNl0sIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKb3R1ID0gZGF0YS5mcmFtZShvdHVfdGFibGUoc2V5X2NvbXBhcnRtZW50LmdlbnVzKSkKCmxlZnNlIDwtIGNiaW5kKHR5cGVfbGVmc2UsIG90dSkKbGVmc2UyIDwtIGNiaW5kKHRheF9uYW1lMix0KGxlZnNlKSkKd3JpdGUudGFibGUobGVmc2UyLCBmaWxlPXBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImxlZnNlX3R5cGVfc2V5LnR4dCIpLCAKICAgICAgICAgICAgc2VwPSJcdCIsIHJvdy5uYW1lcz1GQUxTRSwgY29sLm5hbWVzPUZBTFNFLCBxdW90ZT1GQUxTRSkKYGBgCgpQcm9jZWVkIHRoZSAibGVmc2VfdHlwZV9zZXkudHh0IiBpbiBhIExFZnNlIEdhbGF4eSBhbmQgcmV0cmlldmUgZGF0YSAiTERBIEVmZmVjdCBTaXplIiB3aXRoIHRoZSBhc3NvY2lhdGVkICJQbG90IExFZlNlIFJlc3VsdHMiIGluIHRoZSBMREEgZm9sZGVyLllvdSBoYXZlIHRvIHJlbmFtZSB0aGUgZm9ybWVyIGZpbGUgIkxEQV9yZXN1bHRzIiBhbmQgcnVuIHRoZSBmb2xsb3dpbmcgY29kZS4gCgpgYGB7ciB3cml0ZSBMREEgcmVzdWx0cyxlY2hvID0gVCwgZXZhbD0gRiwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9IApsaWJyYXJ5KHBseXIpCkxEQV9FZmZlY3RfU2l6ZSA8LSByZWFkLmRlbGltKHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgIkxEQV9yZXN1bHRzIiksIGhlYWRlcj1GQUxTRSkKTERBX2d1dCA8LSBzdWJzZXQoTERBX0VmZmVjdF9TaXplICwgTERBX0VmZmVjdF9TaXplJFYzID09ICJHdXQiKQpMREFfYWxnYWUgPC0gc3Vic2V0KExEQV9FZmZlY3RfU2l6ZSAsIExEQV9FZmZlY3RfU2l6ZSRWMyA9PSAiQWxnYWUiKQpMREFfdHlwZSA8LSByYmluZChMREFfZ3V0LExEQV9hbGdhZSkKTERBX3BoeWx1bSA8LSBMREFfdHlwZSRWMQpuYW1lcyhMREFfcGh5bHVtKSA8LSAiLlBoeWx1bS5DbGFzcy5PcmRlci5GYW1pbHkuR2VudXMiCndyaXRlLnRhYmxlKExEQV9waHlsdW0sIGZpbGU9cGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiTERBX3BoeWx1bS50eHQiKSwgc2VwPSJcdCIsIHJvdy5uYW1lcz1GLCBjb2wubmFtZXM9RiwgcXVvdGU9RkFMU0UpCiNwYXN0ZSB0aGUgbmFtZXMoTERBX3BoeWx1bSkgaW4gZXhjZWwgdGhlbiByZWFkIGl0IGFnYWluLgoKbGlicmFyeShyZWFkcikKTERBX3BoeWx1bSA8LSByZWFkX2RlbGltKHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgIkxEQV9waHlsdW0udHh0IiksIi4iLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIGNvbF90eXBlcyA9IGNvbHMoWDEgPSBjb2xfc2tpcCgpKSx0cmltX3dzID0gVFJVRSkKCiNJdCB3aWxsIHRyYW5zZm9ybSBpdCBpbiB0YWJibGUgYW5kIGNvbnZlcnQgIi4iIGJ5IHNlcGFyYXRvciAKTERBX3BoeWx1bV90eXBlIDwtIGNiaW5kKExEQV9waHlsdW0gLCBMREFfdHlwZVssMjo1XSkKY29sbmFtZXMoTERBX3BoeWx1bV90eXBlKSA8LSBjKG5hbWVzKExEQV9waHlsdW0pWzE6NV0gLCAiTERBX3JlcyIgLCAiVHlwZSIgLCAiTERBX3JlczIiICwgInNpZyIpCndyaXRlLnRhYmxlKExEQV9waHlsdW1fdHlwZSwgZmlsZT1wYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMREFfcGh5bHVtX3R5cGUudHh0IiksIHNlcD0iXHQiLCByb3cubmFtZXM9RiwgY29sLm5hbWVzPVQsIHF1b3RlPUZBTFNFKQpMREFfcGh5bHVtX3R5cGUgPC0gcmVhZF9kZWxpbShwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMREFfcGh5bHVtX3R5cGUudHh0IiksIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkKIyBTZWxlY3QgeW91ciBzaWduaWZpY2F0aXYgdmFsdWUgYW5kIHRheGEKTEVGU0Vfc2lnIDwtIHN1YnNldChMREFfcGh5bHVtX3R5cGUsIExEQV9waHlsdW1fdHlwZSRMREFfcmVzMiA+PSAzKQpMRUZTRV9zaWdfZ2VudXMgPC0gc3Vic2V0KExFRlNFX3NpZywgTEVGU0Vfc2lnJEdlbnVzICVpbiUgYXMuY2hhcmFjdGVyKG5hLmV4Y2x1ZGUoTEVGU0Vfc2lnJEdlbnVzKSkpCnRhYmxlKExFRlNFX3NpZ19nZW51cyRUeXBlKQpMRUZTRV9zaWdfZ2VudXNfdmVjIDwtIHBhc3RlKExFRlNFX3NpZ19nZW51cyRQaHlsdW0sIExFRlNFX3NpZ19nZW51cyRDbGFzcywgTEVGU0Vfc2lnX2dlbnVzJE9yZGVyLCBMRUZTRV9zaWdfZ2VudXMkRmFtaWx5LCBMRUZTRV9zaWdfZ2VudXMkR2VudXMsIHNlcCA9ICJ8IikKCmJpb21hcmtlcnMgPC0gcGFzdGUoTEVGU0Vfc2lnX2dlbnVzJE9yZGVyLCBMRUZTRV9zaWdfZ2VudXMkR2VudXMsIHNlcCA9ICJ8IikKc2F2ZShiaW9tYXJrZXJzLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiYmlvbWFya2Vycy5SRGF0YSIpKQoKI3NleV9zYW1wIDwtIHNleV9jb21wYXJ0bWVudC5nZW51c0BzYW1fZGF0YQojd3JpdGUudGFibGUoc2V5X3NhbXAsIGZpbGU9cGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2V5X3NhbXAudHh0IiksIHNlcD0iXHQiLCByb3cubmFtZXM9RiwgY29sLm5hbWVzPVQsIHF1b3RlPUZBTFNFKSAjIFlvdSBuZWVkIHRvIG51bWVyYXRlIHRoZSB0YXgzIG5hbWUgZm9yIHRoZSB0dXJmIGFuZCBzYXJnYXNzdW0gc2FtcGxlcyBhbmQgcmUtcmVhZCBpdC4gCnNleV9zYW1wIDwtIHJlYWRfdGFibGUyKHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNleV9zYW1wLnR4dCIpKQpzYW1wbGVfZGF0YShzZXlfY29tcGFydG1lbnQuZ2VudXMpJHRheDMgPC0gc2V5X3NhbXAkdGF4MwpsZXZlbHMoc2FtcGxlX2RhdGEoc2V5X2NvbXBhcnRtZW50LmdlbnVzKSRsaW5lYWdlKSA8LSBjKCJBbGdhZSIsICJHdXQiKQoKcGh5c2VxX3BoeWx1bSA8LSBzZXlfY29tcGFydG1lbnQuZ2VudXMgJT4lICAgIAogIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGZ1bmN0aW9uKHgpIHt4L3N1bSh4KX0gKSAlPiUgIyBUcmFuc2Zvcm0gdG8gcmVsLiBhYnVuZGFuY2UKICBwc21lbHQoKSAlPiUgIAogIGZpbHRlcihBYnVuZGFuY2UgPiAwKSAlPiUgIyBNZWx0IHRvIGxvbmcgZm9ybWF0CiAgYXJyYW5nZShHZW51cykKCnBoeXNlcV9waHlsdW0kQWJ1bmRhbmNlIDwtIHBoeXNlcV9waHlsdW0kQWJ1bmRhbmNlL25yb3coc2FtcGxlX2RhdGEoc2V5X2NvbXBhcnRtZW50LmdlbnVzKSkKCnBoeXNlcV9waHlsdW0kdGF4IDwtIHBhc3RlKHBoeXNlcV9waHlsdW0kUGh5bHVtLCBwaHlzZXFfcGh5bHVtJENsYXNzLCBwaHlzZXFfcGh5bHVtJE9yZGVyLCBwaHlzZXFfcGh5bHVtJEZhbWlseSwgcGh5c2VxX3BoeWx1bSRHZW51cywgc2VwID0gInwiKQpzYXZlKHBoeXNlcV9waHlsdW0sIGZpbGU9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBoeXNlcV9waHlsdW0uUkRhdGEiKSkKd3JpdGUudGFibGUocGh5c2VxX3BoeWx1bSAsZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBoeXNlcV9waHlsdW0udHh0IiksIHNlcD0iXHQiLHF1b3RlID0gRikKCkRpZXRfUG9sX3NleSA8LSBwaHlzZXFfcGh5bHVtCkRpZXRfUG9sX3NleSR0YXggPC0gIHBhc3RlKERpZXRfUG9sX3NleSRPcmRlciwgRGlldF9Qb2xfc2V5JEdlbnVzLCBzZXAgPSAifCIpCmxlbmd0aChwaHlzZXFfcGh5bHVtJHRheCkKCmRmX3NleSA8LSBEaWV0X1BvbF9zZXlbLGMoImxpbmVhZ2UiLCJTYW1wbGUiLCJ0YXgiLCJBYnVuZGFuY2UiKV0KY29sbmFtZXMoZGZfc2V5KSA8LSBjKCJmYW1pbHkiLCJpdGVtIiwic2NvcmUiLCJ2YWx1ZSIpCnNhdmUoZGZfc2V5LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiZGZfc2V5LlJEYXRhIikpCmBgYAoKTGV0J3Mgb3JnYW5pemUgb3VyIGRhdGEgdG8gcGxvdCBjb3JyZXNwb25kaW5nIGNvbG91cnMgZGVwZW5kaW5nIG9uIHRoZSAgY29tcGFydG1lbnQuIAoKYGBge3IgcG9sYXJoaXN0b2dyYW0gb24gY29tcGFydG1lbnQsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRn0KbG9hZChwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcgLCAiZGZfc2V5LlJEYXRhIikpCmxvYWQocGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nICwgImJpb21hcmtlcnMuUkRhdGEiKSkKCmxpYnJhcnkocGx5cikKcHJpbnRfYmlvbWFya2VycyA8LSBsZXZlbHMoZmFjdG9yKGRmX3NleVtkZl9zZXkkc2NvcmUgJWluJSBiaW9tYXJrZXJzLF0kc2NvcmUpKSAjIEFsbCBiaW9tYXJrZXJzIHByZXNlbnQgaW4gdGhlIHNleS5jb21wYXJ0bWVudF9nZW51cyBSRGF0YSBmaWxlCm90aGVycyA8LSBsZXZlbHMoZmFjdG9yKGRmX3NleVshZGZfc2V5JHNjb3JlICVpbiUgYmlvbWFya2VycyxdJHNjb3JlKSkgIyBBbGwgdGF4YSB3aGljaCBhcmUgbm90IGJpb21hcmtlcnMKZGZfc2V5WyFkZl9zZXkkc2NvcmUgJWluJSBiaW9tYXJrZXJzLF0kc2NvcmUgPC0gIlotT3RoZXIiICMgQ2FsbCB0aGVtIG90aGVyIChaIHRvIGZpZ3VyZSBhdCB0aGUgZW5kIG9mIHRoZSBsaXN0KQoKIyBTb21lIGJpb21hcmtlcnMgYXJlIGluIGNvbW1vbiBzbyBPdXRwdXQgdGhlIGZyZXF1ZW5jZXMuCmZyZXFfZ3V0IDwtIHRhYmxlKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJHdXQiLF0kc2NvcmUpL2xlbmd0aChkZl9zZXlbZGZfc2V5JGZhbWlseSA9PSAiR3V0IixdJHNjb3JlKSoxMDAgCmZyZXFfZ3V0IDwtIGZyZXFfZ3V0WyFuYW1lcyhmcmVxX2d1dCkgPT0gIlotT3RoZXIiXQpmcmVxX2FsZ2FlIDwtIHRhYmxlKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJBbGdhZSIsXSRzY29yZSkvbGVuZ3RoKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJBbGdhZSIsXSRzY29yZSkqMTAwIApmcmVxX2FsZ2FlIDwtIGZyZXFfYWxnYWVbIW5hbWVzKGZyZXFfYWxnYWUpID09ICJaLU90aGVyIl0KCiMgS2VlcCB0aGUgY29tbW9uIGJpb21hcmtlcnMgb2YgdGhlIGFsZ2FlIGFuZCBndXQgYW5kIHRoZSByZXNwZWN0aXZlIGZyZXF1ZW5jaWVzIGluIGVhY2ggY29tcGFydG1lbnQKYmlvbV9jb21tb24gPC0gbmFtZXMoZnJlcV9hbGdhZVt3aGljaChuYW1lcyhmcmVxX2FsZ2FlKSAlaW4lIG5hbWVzKGZyZXFfZ3V0KSldKQpmcmVxX2d1dF9jb21tb24gPC0gYXMuZGF0YS5mcmFtZShmcmVxX2d1dFtuYW1lcyhmcmVxX2d1dCkgJWluJSBiaW9tX2NvbW1vbl0pCmZyZXFfYWxnYWVfY29tbW9uIDwtIGFzLmRhdGEuZnJhbWUoZnJlcV9hbGdhZVtuYW1lcyhmcmVxX2FsZ2FlKSAlaW4lIGJpb21fY29tbW9uXSkKZnJlcV9jb21tb24gPC0gY2JpbmQoZnJlcV9ndXRfY29tbW9uLCBmcmVxX2FsZ2FlX2NvbW1vbiRGcmVxKQpjb2xuYW1lcyhmcmVxX2NvbW1vbikgPC0gYygiQmlvbWFya2VycyIsICJGcmVxX2d1dCIgLCJGcmVxX2FsZ2FlIikKIyBDbGFzcyB0aGUgYmlvbWFya2VycyBpbiB0aGUgY29tcGFydG1lbnQgd2hlcmUgdGhlIHZhbHVlIGlzIHRoZSBoaWdoZXIKYmlvbV9ndXRfdG9fa2VlcCA8LSBmcmVxX2NvbW1vbiRCaW9tYXJrZXJzW3doaWNoKGZyZXFfY29tbW9uJEZyZXFfZ3V0ID4gZnJlcV9jb21tb24kRnJlcV9hbGdhZSwgVCldCmJpb21fYWxnYWVfdG9fa2VlcCA8LSBmcmVxX2NvbW1vbiRCaW9tYXJrZXJzW3doaWNoKGZyZXFfY29tbW9uJEZyZXFfYWxnYWUgPiBmcmVxX2NvbW1vbiRGcmVxX2d1dCwgVCldCiMgU2VlIHdoaWNoIGFyZSB0aGUgYmlvbWFya2VycyBmb3IgdGhlIGd1dCBhbmQgd2hpY2ggYXJlIHRoZSBiaW9tYXJrZXJzIGZvciB0aGUgYWxnYWUKYmlvbV9ndXQgPC0gbGV2ZWxzKGZhY3RvcihkZl9zZXlbZGZfc2V5JGZhbWlseSA9PSAiR3V0IixdJHNjb3JlKSkKYmlvbV9ndXQgPC0gYmlvbV9ndXRbIWJpb21fZ3V0ID09ICJaLU90aGVyIl0KYmlvbV9ndXQgPC0gYmlvbV9ndXRbIWJpb21fZ3V0ICVpbiUgYmlvbV9hbGdhZV90b19rZWVwXQpiaW9tX2FsZ2FlIDwtIGxldmVscyhmYWN0b3IoZGZfc2V5W2RmX3NleSRmYW1pbHkgPT0gIkFsZ2FlIixdJHNjb3JlKSkKYmlvbV9hbGdhZSA8LSBiaW9tX2FsZ2FlWyFiaW9tX2FsZ2FlID09ICJaLU90aGVyIl0KYmlvbV9hbGdhZSA8LSBiaW9tX2FsZ2FlWyFiaW9tX2FsZ2FlICVpbiUgYmlvbV9ndXRfdG9fa2VlcF0KCiMgQ29sb3IgY2hvaWNlCmFsZ2FlX2NvbG9ycyA8LSBjKCJkYXJrZ3JlZW4iICwgImRhcmtraGFraSIsICJkYXJrb2xpdmVncmVlbiIsCiAgICAgICAgICAgICAgICAgICJkYXJrb2xpdmVncmVlbjIiLCJmb3Jlc3RncmVlbiIsImNoYXJ0cmV1c2UiLAogICAgICAgICAgICAgICAgICAiYXF1YW1hcmluZSIsImFxdWFtYXJpbmUzIiwgImRhcmtjeWFuIiwKICAgICAgICAgICAgICAgICAgImRhcmtzZWFncmVlbiIsICJ5ZWxsb3dncmVlbiIsICJkYXJrc2xhdGVncmF5IiwKICAgICAgICAgICAgICAgICAgImdvbGQzIiwgImdvbGQ0IiwgImdvbGRlbnJvZCIsCiAgICAgICAgICAgICAgICAgICJnb2xkIiwicGFsZWdyZWVuNCIsImNoYXJ0cmV1c2UzIiwKICAgICAgICAgICAgICAgICAgInBhbGVncmVlbjMiLCAic2VhZ3JlZW4zIiwicGFsZWdvbGRlbnJvZCIsInllbGxvdyIpCnBpZShyZXAoMSwgMjIpLCBjb2w9IGFsZ2FlX2NvbG9ycykKCmd1dF9jb2xvcnMgPC0gYygiYnJvd24iLCAiYnJvd24xIiwgImJ1cmx5d29vZDQiLAogICAgICAgICAgICAgICAgImNob2NvbGF0ZSIsImNob2NvbGF0ZTQiLCAiY29yYWwyIiwKICAgICAgICAgICAgICAgICJkYXJrc2FsbW9uIiwiZGFya3JlZCIsImRhcmtvcmNoaWQ0IiwKICAgICAgICAgICAgICAgICJkYXJrbWFnZW50YSIsICJibHVldmlvbGV0IiwiZGFya2JsdWUiLAogICAgICAgICAgICAgICAgImJsdWUzIiwgImRlZXBwaW5rNCIsImRlZXBwaW5rIikKcGllKHJlcCgxLCAxNSksIGNvbD0gZ3V0X2NvbG9ycykKcG9sYXJfY29sIDwtIGMoYWxnYWVfY29sb3JzICwgZ3V0X2NvbG9ycyAsICdaX090aGVyJz0iYmxhY2siKQojIEFkZCBhIHByZWZpeCBHIChmb3IgZ3V0KSBvciBBIChmb3IgYWxnYWUpIGluIHRoZWlyIHJlc3BlY3RpdiBiaW9tYXJrZXJzLiBJbiB0aGlzIHdheSwgdGhleSB3aWxsIGJlIGxpc3RlZCBmb2xsb3dpbmcgCiMgdGhlaXIgcmVzcGVjdGl2IGNvbXBhcnRtZW50IGFuZCBubyB0aGVpciBuYW1lcyAoZWFzaWVyIGZvciB0aGUgYWRkIG9mIHRoZSBjb2xvciBpbiB0aGUgZ2dwbG90KQpkZl9zZXlbZGZfc2V5JHNjb3JlICVpbiUgYmlvbV9ndXQsXSRzY29yZSA8LSBwYXN0ZSgiRyIsZGZfc2V5W2RmX3NleSRzY29yZSAlaW4lIGJpb21fZ3V0LF0kc2NvcmUsIHNlcD0gIi0iKQpkZl9zZXlbZGZfc2V5JHNjb3JlICVpbiUgYmlvbV9hbGdhZSxdJHNjb3JlIDwtIHBhc3RlKCJBIixkZl9zZXlbZGZfc2V5JHNjb3JlICVpbiUgYmlvbV9hbGdhZSxdJHNjb3JlLCBzZXA9ICItIikKYGBgCgpXZSB1c2UgdGhlIHNjcmlwdCBvZiBbTGFkcm91ZSBldCBhbC4sKDIwMTIpXShodHRwOi8vZHguZG9pLm9yZy8xMC4xMDM4L25nLjEwNzMuKSB0byBkcmF3IHRoZSBoaXN0b2dyYW0gd2l0aCB0aGUgYHBvbGFySGlzdG9ncmFtYCBmdW5jdGlvbiBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9idXJha2F5ZGluL21hdGVyeWFsbGVyL2Jsb2IvbWFzdGVyL211Z2xhX2VqZVIvcG9sYXJIaXN0b2dyYW0uUikuCgpgYGB7ciBQcmludCB0aGUgcG9sYXJoaXN0b2dyYW1tLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0Kc291cmNlKHBhc3RlMChkaXJfcmVmZGIsICJwb2xhckhpc3RvZ3JhbS5SIikpCnAgPC0gcG9sYXJIaXN0b2dyYW0oZGZfc2V5ICwgZmFtaWx5TGFiZWw9VCwgaW5uZXJSYWRpdXMgPSAwLjIsIHNwYWNlRmFtaWx5ID03LCBjaXJjbGVQcm9wb3J0aW9uID0gMC44NSkKcCArIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gcG9sYXJfY29sKSArCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiwgc2l6ZSA9IDMpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSAibm9uZSIpICMgdG8gaGlkZSB0aGUgbGVnZW5kIGJlY2F1c2Ugb2YgdGhlIHNpemUKYGBgCgojIyMjIENvbmNsdXNpb24KPHN0eWxlPgpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I0ZCREZCNDsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJibHVlIj4KPGZvbnQgc2l6ZT0iNCI+IFRoZSBtaWNyb2JpYWwgY29tcG9zaXRpb25zIGJldHdlZW4gYWxnYWUgYW5kIHRoZSBndXQgb2YgcmVlZiBmaXNoIGlzIHZlcnkgZGlmZmVyZW50IHdpdGggbWFueSAqKmFlcm9iaWMgZ3JvdXBzIGZvciB0aGUgbWFjcm9hbGdhZSBhbmQgbW9zdCBvZiBhbGwgYW5hZXJvYmljIGZvciB0aGUgZW50ZXJpYyBjb3JlIG1pY3JvYmlvbWVzKiouIFRoZSBibGFzdCBhbmFseXNlcyBjb25maXJtIHRoZSBzb3VyY2Ugb2Ygb3VyIEFTVnMgd2hpY2ggYXJlIG1haW5seSBhc3NvY2lhdGVkIHdpdGggYW5pbWFsIGhvc3QgbWFyaW5lIG1pY3JvYmlvbWVzLiBUaGVpciByb2xlIGhhdmUgYmVlbiBkZXNjcmliZWQgYXMgaW1wb3J0YW50IGluIHRoZSBmdW5jdGlvbiBvZiAqKm51dHJpdGlvbioqICgqZS5nLiogVmlicmlvbmFsZXMsIENsb3N0cmlkaWFsZXMpLgpBIGZpcnN0IG9ic2VydmF0aW9uIHJlbWFpbnMgb2YgdGhlIHZlcnkgKipoaWdoIGFuZCBpbXByZXNzaXZlIHZhcmlhYmlsaXR5KiogYmV0d2VlbiBlbnRlcmljIGNvcmUgbWljcm9iaW9tZXMuIE5vdywgd2Ugd29uZGVyIHdoYXQgd291bGQgYmUgdGhlIG9yaWdpbiBvZiBhIHN1Y2ggdmFyaWFiaWxpdHkgYnkgdGVzdGluZyB0aGUgKmRpZXQqLCB0aGUgKnRheG9ub21pYyBlZmZlY3QqIGFuZCB0aGUgKmVmZmVjdCBvZiB0aGUgZW52aXJvbm1lbnQqIGFzIHBvc3NpYmxlIGRldGVybWluYW50IG9mIHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgbWljcm9iaW9tZS4KPC9kaXY+Cgo8YSBpZD0iUGFydCBWOiBJbmZsdWVuY2Ugb2YgdGhlIGNvcmFsLW1hY3JvbGFnYWwgc2hpZnQgb24gbWljcm9iaWFsIGNvbXBvc2l0aW9ucyI+PC9hPiAKCiMjIFBhcnQgVjogSW5mbHVlbmNlIG9mIHRoZSBjb3JhbC1tYWNyb2xhZ2FsIHNoaWZ0IG9uIG1pY3JvYmlhbCBjb21wb3NpdGlvbnMKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpPdXIgbWFpbiBpc3N1ZSBpcyB0byAqZGV0ZXJtaW5lIGlmIHRoZSBzaGlmdCBjb3JhbC1tYWNyb2FsZ2FsIGluIHRoZSBTZXljaGVsbGVzIHJlZWZzIHdvdWxkIGluZmx1ZW5jZSB0aGUgY29tcG9zaXRpb24gb2YgdGhlIGNvcmUgbWljcm9iaW9tZSBvZiB0aGVpciBpbmhhYml0YW50cyouIFRvIHRlc3QgdGhhdCwgd2Ugd2lsbCBmaXJzdCBhbmFseXNlIHRoZSBpbmZsdWVuY2Ugb24gdGhlIGVudmlyb25tZW50YWwgbWljcm9iaW9tZSB0aHJvdWdoIHRoZSBhbGdhZS4gVGhlbiwgYmVjYXVzZSBhIG1vZGlmaWNhdGlvbiBvZiB0aGUgbWljcm9iaWFsIGVudmlyb25tZW50IHdvdWxkIGRpcmVjdGx5IG1vZGlmeSB0aGUgbWljcm9iaW9tZSBvZiB0aGVpciBjb25zdW1tZXIgKGhlcmUsIHRoZSBoZXJiaXZvcmVzIGFuZCBpbmRpcmVjdGx5IHRoZSBpbnZlcnRpdm9yZXMpLCB3ZSB3aWxsIHRlc3QgdGhlIGVmZmVjdCBvZiB0aGUgc2hpZnQgb24gdGhlc2UgYm90aCBjb21tdW5pdGllcy4gV2Ugc2F3IHRoYXQgY29yZSBtaWNyb2Jpb21lIHdhcyBoaWdobHkgdmFyaWFibGUgYmV0d2VlbiBpbmRpdmlkdWFscy4gVGhlIHRheG9ub21pYyBlZmZlY3QgaXMgYWxyZWFkeSBrbm93biB0byBiZSBhIG1ham9yIGRldGVybWluYW50IGluIHRoZSBtaWNyb2JpYWwgY29tcG9zaXRpb24gaW4gZmlzaGVzLiBUaGF0IGlzIHdoeSwgd2Ugd2lsbCB0ZXN0IHRoZSBpbmZsdWVuY2Ugb2YgdGhlIHNoaWZ0IGF0IGRpZmZlcmVudCB0YXhvbm9taWNhbCBsZXZlbHMgKGZhbWlseSwgZ2VudXMgYW5kIHNwZWNpZXMpIHdoZW4gdGhlIHNhbXBsaW5nIHNpemUgd2FzIHN1ZmZpY2llbnQuCgojIyMgUGFydCBWYSA6IFNoaWZ0IGltcGFjdCBvbiB0aGUgY29yZSBtaWNyb2Jpb21lIG9mIEFsZ2FlCltiYWNrIHRvIHRvcF0oI2JhY2sgdG8gdG9wKQoKV2Ugd2lsbCBmaXJzdCBjcmVhdGUgb25jZSBhZ2FpbiBhIG5ldyBmb2xkZXIgZm9yIHRoZSBlZmZlY3Qgb2YgdGhlIHNoaWZ0IGFuZCBvdGhlciBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMgYW5kIHRlc3QgYm90aCBvbiBhbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkuCgpgYGB7ciBzaGlmdCBhbGdhZSB3ZCAsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0FsZ2FlL1NoaWZ0LyIpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFQpCmBgYAoKIyMjIyBBbHBoYSBkaXZlcnNpdHkKYGBge3IgYWxwaGEtZGl2IGFsZ2FlIGJ5IHNoaWZ0LCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KbG9hZChwYXN0ZTAoZGlyX3RheGFfYXNzaWduLCAic2V5cmZmX2FsZ2FlLlJEYXRhIikpCmJveDEgPSBwbG90X3JpY2huZXNzKHNleXJmZl9hbGdhZSAsIG1lYXN1cmVzID0gYygiT2JzZXJ2ZWQiLCJTaGFubm9uIikgLCBjb2xvciA9ICJnZW9tb3JwaG8iKQojIF9fX18gU2hhbm5vbiBpbmRleCAoRU5TKQpib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlID0gZXhwKGJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUpCmxldmVscyhib3gxJGRhdGEkdmFyaWFibGUpPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpib3gxJGRhdGEkZ2VvbW9ycGhvIDwtIHN0cl9yZXBsYWNlX2FsbChib3gxJGRhdGEkZ2VvbW9ycGhvLCBjKCJtYWNyb2FsZ2FsIj0gIk0iICwgImNvcmFsIj0iQyIpKQoKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ3Bsb3QyKQpwYWxldHRlID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikKCnNleV9hbGdhZV9hbHBoYV9kaXYgPSAgZ2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyAKICB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAxOCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIAogICAgICAgICAgICAgIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLCB0ZXh0c2l6ZT01LCBjb2xvcj0iYmxhY2siLCBmYW1pbHkgPSAic2VyaWYiKQoKc2V5X2FsZ2FlX2FscGhhX2RpdgojIF9fX18gVGVzdCBNVyAtLS0tCmxpYnJhcnkocGdpcm1lc3MpCiMgRG9lcyBleGlzdCBkaWZmZXJlbmNlcyBpbiBkaXZlcnNpdHkgYmV0d2VlbiB0eXBlcyBvZiBob3N0PyAKIyBfX19fX19fX19fX18gT2JzZXJ2ZWQgcmljaG5lc3MgTVcgCk1XLm9icyA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXSkKTVcub2JzID0gY2JpbmQoTVcub2JzJHN0YXRpc3RpYywgTVcub2JzJHAudmFsdWUpCiMgX19fX19fX19fX19fIFNoYW5ub24gbnVtYmVyIE1XIApNVy5zaGFubm9uID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSkKTVcuc2hhbm5vbiA9Y2JpbmQoTVcuc2hhbm5vbiRzdGF0aXN0aWMsIE1XLnNoYW5ub24kcC52YWx1ZSkKIyBfX19fX19fX19fX18gQWxsIGNvbXB1dGVkIApNVy50ZXN0IDwtIHJiaW5kKE1XLm9icywgTVcuc2hhbm5vbikKcm93bmFtZXMoTVcudGVzdCkgPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpjb2xuYW1lcyhNVy50ZXN0KSA9IGMoJ1cgc3RhdCcgLCAncC12YWx1ZScpCk1XLnRlc3QKYGBgCgojIyMjIEJldGEgZGl2ZXJzaXR5IApgYGB7ciBiZXRhLWRpdiBhbGdhZSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciIgfQpsb2FkKHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvQWxnYWUvQ29yZS9zZXlfYWxnYWVfY29yZS5SRGF0YSIpKQpjb3JlX2FsZ2FlX3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhzZXlfYWxnYWVfY29yZSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSApCnNhdmUoY29yZV9hbGdhZV9yZWwgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9hbGdhZV9yZWwuUkRhdGEiKSkKCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoYXBlKQpvdHUgPC0gdmVnZGlzdChjb3JlX2FsZ2FlX3JlbEBvdHVfdGFibGUsIG1ldGhvZCA9ICJicmF5IikKc2F2ZShvdHUsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiZXRhX21hdHJpY2VzLlJEYXRhIikpCnBjb2Euc3ViIDwtIHBjb2Eob3R1KQpzYXZlKHBjb2Euc3ViLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicGNvYS52YWx1ZXMuUkRhdGEiKSkKCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKGNvcmVfYWxnYWVfcmVsKSkKc2F2ZShzYW1wX2RhdGEsZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNhbXBfZGF0YS5SRGF0YSIpKQpodWxsIDwtIGNiaW5kKHBjb2FfY29vcmQsIHNhbXBfZGF0YSkKaHVsbCRnZW9tb3JwaG8gPC0gc3RyX3JlcGxhY2VfYWxsKGh1bGwkZ2VvbW9ycGhvLCBjKCJtYWNyb2FsZ2FsIj0gIk0iICwgImNvcmFsIj0iQyIpKQoKIyBXaGF0IGlzIHRoZSBwZXJjZW50YWdlIG9mIHRoZSBleHBsaWNhdGl2ZSB2YXJpYW5jZT8gCnBhc3RlKCJBeGlzIDEgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKSkgCnBhc3RlKCJBeGlzIDIgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKSkgCnBhc3RlKCJBeGlzIDMgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzNdKSkKcGFzdGUoIkF4aXMgNCA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbNF0pKQoKcGFsZXR0ZSA9IGMoImRhcmtibHVlIiwiZGFya3JlZCIpCnBjb2EgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGh1bGwsIGFlcyh4PUF4aXMuMSwgeT1BeGlzLjIsIGNvbG9yID0gZ2VvbW9ycGhvKSwgYWxwaGEgPSAwLjcsIHNpemUgPSAzLCBzaGFwZSA9IDE3KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpKwogIHhsYWIocGFzdGUoIlBDbzEgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0qMTAwLCAxKSwgIiUpIikpICsKICB5bGFiKHBhc3RlKCJQQ28yICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSksICIlKSIpKSAgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwgIyByZW1vdmUgeC1heGlzIGxhYmVscwogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsIHNpemUgPSAxNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLGZhbWlseSA9ICJzZXJpZiIpKSArCiAgbGFicyhjb2xvdXIgPSAiU2l0ZSIsIGZpbGwgPSAiUmVlZiIpCnBjb2EKCiMgX19fX18gUGVybWFub3ZhcyBhbmQgQmV0YWRpc3BlciAgLS0tLS0tCnNhbXBfZGF0YSA8LSByZWFkX2RlbGltKHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywic2FtcF9kYXRhLnR4dCIpLCJcdCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUpCmBgYAoKTGV0J3MgdGVzdCB0aGUgZGlmZmVyZW50IG1pY3JvYmlhbCBjb21wb3NpdGlvbnMgaW4gZnVuY3Rpb24gb2YgdGhlIGdlb21vcnBob2xvZ3kgb2YgdGhlIHNpdGUgKGNvcmFsIG9yIG1hY3JvYWxnYWwgY292ZXIpLCB0aGUgc2l0ZSBhbmQgdGhlIHN1YnN0cmF0YS4gCgpgYGB7ciBhbGdhbCBlbnYxICwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGIH0KIyBCZXR3ZWVuIGdlb21vcnBobywgc2l0ZSAsIHN1YnN0cmF0CmFkb25pcyhvdHUgfiBnZW9tb3JwaG8sIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhvdHUgfiBzaXRlLCBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMob3R1IH4gc3Vic3RyYXQsIGRhdGEgPSBzYW1wX2RhdGEpCmBgYAoKQmVjYXVzZSB3ZSBoYWQgdHdvIHR5cGVzIG9mIG1hY3JvYWxnYWUsIGFuZCBvdmVyYWxsIHR3byBkaWZmZXJlbnQgY2xhZGVzIChicm93biBtYWNyb2FsZ2FlIHdpdGggdGhlICpTYXJnYXNzdW0qIGFuZCBhIGdyZWVuIG1hY3JvYWxnYWUgd2l0aCB0aGUgdHVyZiluLCB3ZSB0ZXN0ZWQgaWYgdGhlIGVudmlyb25tZW50IHdvdWxkIGFsd2F5cyBwbGF5cyBhIHJvbGUgaW5zaWRlIGEgdHlwZSBvZiBhbGdhZS4gCgpgYGB7ciBhbGdhbCBlbnYyICwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQphZG9uaXMob3R1IH4gdHlwZS9nZW9tb3JwaG8sIHN0cmF0YT0gc2FtcF9kYXRhJHR5cGUsIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhvdHUgfiB0eXBlL3NpdGUsIHN0cmF0YT0gc2FtcF9kYXRhJHR5cGUsIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhvdHUgfiB0eXBlL3N1YnN0cmF0LCBzdHJhdGE9IHNhbXBfZGF0YSR0eXBlLCBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMob3R1IH4gdHlwZS9pc2xhbmQsIHN0cmF0YT0gc2FtcF9kYXRhJHR5cGUsIGRhdGEgPSBzYW1wX2RhdGEpCmBgYAoKCiMjIyBQYXJ0IFZiIDogU2hpZnQgaW1wYWN0IG9uIHRoZSBlbnRlcmljIGNvcmUgbWljcm9iaW9tZSBvZiBSZWVmIGZpc2gKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgojIyMjICoqSGVyYml2b3JlcyoqCgpXZSBoYXZlIDMgZmFtaWxpZXMgb2YgaGVyYml2b3JlcyA6IHRoZSBzY3JhcHBlcnMgU2NhcmlkYWUgYW5kIHRoZSBicm93c2VycyBBY2FudGh1cmlkYWUgYW5kIFNpZ2FuaWRhZS4gVW5mb3J0dW5hdGVseSwgdGhlIG9ubHkgaW5kaXZpZHVhbHMgcHJlc2VudCBpbiB0aGUgaW1wYWN0ZWQgc2hpZnRlZCBzaXRlcyB3ZXJlIHRocmVlICpTY2FydXMgZ2hvYmJhbiouCk5ldmVydGhlbGVzcywgd2UgdHJpZWQgdG8gZGV0ZXJtaW5lIHdoaWNoIHdlcmUgdGhlIG90aGVyIGRldGVybWluYW50IGluIGVhY2ggY29tcG9uZW50cyBhbmQgdGVzdCB0aGUgZWZmZWN0IG9mIG90aGVyIGVudmlyb25tZW50YWwgcGFyYW1ldGVycy4gCgojIyMjIEhlcmJpdm9yb3VzIGNvbW11bml0eQoKYGBge3IgaGVyYiB3ZCwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGIH0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL1NoaWZ0L0hlcmIvIikKZGlyLmNyZWF0ZShkaXJfZGF0YV9jbGVhbmluZywgcmVjdXJzaXZlID0gVCkKYGBgCgpXZSBuZWVkIHRvIHN1YnNldCBmcm9tIHRoZSBgc2V5X2d1dGAgcGh5bG9zZXEgb2JqZWN0IHRoZSBoZXJiaXZvcm91cyBmaXNoZXMuIAoKYGBge3IgaGVyYiBwaHlzZXEgY3JlYXRpb24gLGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiB9CmhlcmJfcHMgPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dCwgZGlldDMgPT0gIkhlcmJpdm9yb3VzIikKaGVyYl9wcyA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoaGVyYl9wc0BvdHVfdGFibGUpPjApKSwgaGVyYl9wcykKc2F2ZShoZXJiX3BzLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiaGVyYl9wcy5SRGF0YSIpKQpyZmZfaGVyYiA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKGhlcmJfcHMpID49IG1pbihzYW1wbGVfc3VtcyhoZXJiX3BzKSkgLCBoZXJiX3BzKQpyZmZfaGVyYiA8LSByYXJlZnlfZXZlbl9kZXB0aChoZXJiX3BzICxtaW4oc2FtcGxlX3N1bXMoaGVyYl9wcykpKQpzYXZlKHJmZl9oZXJiICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInJmZl9oZXJiLlJEYXRhIikpCmhlcmJfY29yZSA8LSBzdWJzZXRfc2FtcGxlcyhzZXlfZ3V0X2NvcmUsIGRpZXQzID09ICJIZXJiaXZvcm91cyIpCmhlcmJfY29yZSA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoaGVyYl9jb3JlQG90dV90YWJsZSk+MCkpLCBoZXJiX2NvcmUpCnNhdmUoaGVyYl9jb3JlLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiaGVyYl9jb3JlLlJEYXRhIikpCmBgYAoKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CmBgYHtyIGFscGhhIGhlcmIsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSAiY2VudGVyIn0KYm94MSA9IHBsb3RfcmljaG5lc3MocmZmX2hlcmIgLCBtZWFzdXJlcyA9IGMoIk9ic2VydmVkIiwiU2hhbm5vbiIpICwgY29sb3IgPSAiZ2VvbW9ycGhvIikKYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSA9IGV4cChib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlKQpsZXZlbHMoYm94MSRkYXRhJHZhcmlhYmxlKT0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKbGV2ZWxzKGJveDEkZGF0YSRnZW9tb3JwaG8pID0gYygiQyIgLCAiTSIpCgpwYWxldHRlID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikKc2V5X2hlcmJfYWxwaGFfZGl2PSAgZ2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyNCwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLAogICAgICAgICAgICAgIHRleHRzaXplPTUsIGNvbG9yPSJibGFjayIsIGZhbWlseSA9ICJzZXJpZiIsIHZqdXN0ID0gMC4xKQoKc2V5X2hlcmJfYWxwaGFfZGl2IAojIF9fX19fX19fX19fXyBPYnNlcnZlZCByaWNobmVzcyBNVyAKTVcub2JzID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdKQpNVy5vYnMgPSBjYmluZChNVy5vYnMkc3RhdGlzdGljLCBNVy5vYnMkcC52YWx1ZSkKIyBfX19fX19fX19fX18gU2hhbm5vbiBudW1iZXIgTVcgCk1XLnNoYW5ub24gPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdKQpNVy5zaGFubm9uID1jYmluZChNVy5zaGFubm9uJHN0YXRpc3RpYywgTVcuc2hhbm5vbiRwLnZhbHVlKQojIF9fX19fX19fX19fXyBBbGwgY29tcHV0ZWQgCk1XLnRlc3QgPC0gcmJpbmQoTVcub2JzLCBNVy5zaGFubm9uKQpyb3duYW1lcyhNVy50ZXN0KSA9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwiU2hhbm5vbiAoRU5TKSIpCmNvbG5hbWVzKE1XLnRlc3QpID0gYygnVyBzdGF0JyAsICdwLXZhbHVlJykKTVcudGVzdApgYGAKCmBgYHtyIGJldGEgaGVyYiwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ICJjZW50ZXIifQpjb3JlX2hlcmJfcmVsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGhlcmJfY29yZSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSApCnNhdmUoY29yZV9oZXJiX3JlbCAgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9oZXJiX3JlbC5SRGF0YSIpKQojIF9fX19fIFBDT0EgY29kYSAmIHBlcm1hbm92YSAtLS0tLS0KbWF0cml4IDwtIHZlZ2Rpc3QoY29yZV9oZXJiX3JlbEBvdHVfdGFibGUsIG1ldGhvZCA9ICJicmF5IikKc2F2ZShtYXRyaXgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiZXRhX21hdHJpY2VzLlJEYXRhIikpCnBjb2Euc3ViIDwtIHBjb2EobWF0cml4KQpzYXZlKHBjb2Euc3ViLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicGNvYS52YWx1ZXMuUkRhdGEiKSkKCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKGNvcmVfaGVyYl9yZWwpKQpzYXZlKHNhbXBfZGF0YSxmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLlJEYXRhIikpCiN3cml0ZS50YWJsZShzYW1wX2RhdGEsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEudHh0IiksIHF1b3RlID0gRiwgc2VwID0gIlx0IikKaHVsbCA8LSBjYmluZChwY29hX2Nvb3JkLCBzYW1wX2RhdGEpCmh1bGwkZ2VvbW9ycGhvIDwtIHN0cl9yZXBsYWNlX2FsbChodWxsJGdlb21vcnBobywgYygibWFjcm9hbGdhbCI9ICJNIiAsICJjb3JhbCI9IkMiKSkKCnBhc3RlKCJBeGlzIDEgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKSkgCnBhc3RlKCJBeGlzIDIgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKSkgCnBhc3RlKCJBeGlzIDMgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzNdKSkKcGFzdGUoIkF4aXMgNCA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbNF0pKQoKcGNvYV9oZXJiIDwtIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBodWxsLCBhZXMoeD1BeGlzLjEsIHk9QXhpcy4yLCBjb2xvciA9IGdlb21vcnBobywgc2hhcGUgPSBmYW1pbHkpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkrCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTYsMTcsMTgpKSsKICB4bGFiKHBhc3RlKCJQQ28xICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSksICIlKSIpKSArCiAgeWxhYihwYXN0ZSgiUENvMiAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSoxMDAsIDEpLCAiJSkiKSkgICsKICB0aGVtZV9idygpICsKICBjb29yZF9lcXVhbCgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCwgZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHgtYXhpcyBsYWJlbHMKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCAsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB5LWF4aXMgbGFiZWxzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtYWpvci1ncmlkIGxhYmVscwogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1pbm9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSkrCiAgbGFicyhjb2xvdXIgPSAiUmVlZiIpCnBjb2FfaGVyYgpgYGAKClBlcm1hbm92YSBvbiB0aGUgb25seSBlZmZlY3Qgb2YgdGhlIGdlb21vcnBobyBidXQgdGhlcmUgaXMgYSBsb3Qgb2YgdmFyaWFiaWxpdHkuLi4KYGBge3IgcGVybWFub3ZhIGhlcmIxLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmFkb25pcyhtYXRyaXggfiBnZW9tb3JwaG8sIGRhdGEgPSBzYW1wX2RhdGEpCmBgYAoKUEVSTUFOT1ZBcyBvbiB0aGUgdGF4b25vbWljIGVmZmVjdCBiZXR3ZWVuICBnZW51cyBhbmQgc3BlY2llcyB3aXRoaW4gZmFtaWxpZXMKCmBgYHtyIHBlcm1hbm92YSBoZXJiMiwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQphZG9uaXMobWF0cml4IH4gZmFtaWx5L2dlbnVzL3RheDEsIHN0cmF0YT0gc2FtcF9kYXRhJGZhbWlseSwgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCkFuZCBiZXR3ZWVuIHNwZWNpZXMvc2l0ZSAsIGJldHdlZW4gc3BlY2llcy9nZW9tb3JwaG8sIGFuZCBzcGVjaWVzL3N1YnN0cmF0YSBpbnNpZGUgZmFtaWxpZXMKYGBge3IgcGVybWFub3ZhIGhlcmIzLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmFkb25pcyhtYXRyaXggfiB0YXgxL3NpdGUsIHN0cmF0YT0gc2FtcF9kYXRhJGZhbWlseSwgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IHRheDEvZ2VvbW9ycGhvLCBzdHJhdGE9IHNhbXBfZGF0YSRmYW1pbHksIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhtYXRyaXggfiB0YXgxL3N1YnN0cmF0LCBzdHJhdGE9IHNhbXBfZGF0YSRmYW1pbHksIGRhdGEgPSBzYW1wX2RhdGEpCmBgYAoKVGhlcmUgaXMgYSBzaWduaWZpY2FudCBlZmZlY3Qgb2YgdGhlIHRheG9ub21pYyBlZmZlY3QgZXZlbiBhdCBmYW1pbHkgbGV2ZWwuIFRvIGVyYXNlIHRoaXMgZWZmZWN0LCB3ZSBmb2N1c2VkIG91ciB0ZXN0cyBvbiBTY2FyaWRhZSBtZW1iZXJzLiAKCiMjIyMgU2NhcmlkYWUgZmFtaWx5CgpgYGB7ciBzY2FyaWRhZSBmYW1pbHkgd2QgLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvRmlzaC9TaGlmdC9TY2FyaWRhZS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKc2NhcmlkYWVfcHMgPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dCwgZmFtaWx5ID09ICJTY2FyaWRhZSIpCnNjYXJpZGFlX3BzIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhzY2FyaWRhZV9wc0BvdHVfdGFibGUpPjApKSwgc2NhcmlkYWVfcHMpCnNhdmUoc2NhcmlkYWVfcHMsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzY2FyaWRhZV9wcy5SRGF0YSIpKQpzY2FyaWRhZXJmZiA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKHNjYXJpZGFlX3BzKSA+PSBtaW4oc2FtcGxlX3N1bXMoc2NhcmlkYWVfcHMpKSAsIHNjYXJpZGFlX3BzKQpzY2FyaWRhZXJmZiA8LSByYXJlZnlfZXZlbl9kZXB0aChzY2FyaWRhZV9wcyAsbWluKHNhbXBsZV9zdW1zKHNjYXJpZGFlX3BzKSkpCnNhdmUoc2NhcmlkYWVyZmYgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2NhcmlkYWVyZmYuUkRhdGEiKSkKc2Nhcl9jb3JlIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgZmFtaWx5ID09ICJTY2FyaWRhZSIpCnNjYXJfY29yZSA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoc2Nhcl9jb3JlQG90dV90YWJsZSk+MCkpLCBzY2FyX2NvcmUpCnNhdmUoc2Nhcl9jb3JlLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2Nhcl9jb3JlLlJEYXRhIikpCmBgYAoKIyMjIyBBbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkKCmBgYHtyIGFscGhhIHNjYXJpZGFlLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciJ9CmJveDEgPSBwbG90X3JpY2huZXNzKHNjYXJpZGFlcmZmICwgbWVhc3VyZXMgPSBjKCJPYnNlcnZlZCIsIlNoYW5ub24iKSAsIGNvbG9yID0gImdlb21vcnBobyIpCiMgX19fXyBTaGFubm9uIGluZGV4IChFTlMpCmJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUKYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSA9IGV4cChib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlKQpsZXZlbHMoYm94MSRkYXRhJHZhcmlhYmxlKT0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKbGV2ZWxzKGJveDEkZGF0YSRnZW9tb3JwaG8pID0gYygiQyIgLCAiTSIpCgpwYWxldHRlID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikKCnNleV9zY2FyaWRhZV9hbHBoYV9kaXY9Z2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyNCwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLCB0ZXh0c2l6ZT01LCBjb2xvcj0iYmxhY2siLCBmYW1pbHkgPSAic2VyaWYiKQoKc2V5X3NjYXJpZGFlX2FscGhhX2RpdiAKCiMgX19fXyBUZXN0IE1XIC0tLS0KbGlicmFyeShwZ2lybWVzcykKIyBEb2VzIGV4aXN0IGRpZmZlcmVuY2VzIGluIGRpdmVyc2l0eSBiZXR3ZWVuIHR5cGVzIG9mIGhvc3Q/IAojIF9fX19fX19fX19fXyBPYnNlcnZlZCByaWNobmVzcyBNVyAKTVcub2JzID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdKQpNVy5vYnMgPSBjYmluZChNVy5vYnMkc3RhdGlzdGljLCBNVy5vYnMkcC52YWx1ZSkKIyBfX19fX19fX19fX18gU2hhbm5vbiBudW1iZXIgTVcgCk1XLnNoYW5ub24gPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdKQpNVy5zaGFubm9uID1jYmluZChNVy5zaGFubm9uJHN0YXRpc3RpYywgTVcuc2hhbm5vbiRwLnZhbHVlKQojIF9fX19fX19fX19fXyBBbGwgY29tcHV0ZWQgCk1XLnRlc3QgPC0gcmJpbmQoTVcub2JzLCBNVy5zaGFubm9uKQpyb3duYW1lcyhNVy50ZXN0KSA9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwiU2hhbm5vbiAoRU5TKSIpCmNvbG5hbWVzKE1XLnRlc3QpID0gYygnVyBzdGF0JyAsICdwLXZhbHVlJykKTVcudGVzdApgYGAKCmBgYHtyIGJldGEgc2NhcmlkYWUsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSAiY2VudGVyIn0Kc2Nhcl9jb3JlX3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhzY2FyX2NvcmUsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkgKQpzYXZlKHNjYXJfY29yZV9yZWwgICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNjYXJfY29yZV9yZWwuUkRhdGEiKSkKIyBfX19fXyBQQ09BIGNvZGEgJiBwZXJtYW5vdmEgLS0tLS0tCm1hdHJpeCA8LSB2ZWdkaXN0KHNjYXJfY29yZV9yZWxAb3R1X3RhYmxlLCBtZXRob2QgPSAiYnJheSIpCnNhdmUobWF0cml4LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiYmV0YV9tYXRyaWNlcy5SRGF0YSIpKQpwY29hLnN1YiA8LSBwY29hKG1hdHJpeCkKc2F2ZShwY29hLnN1YiwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBjb2EudmFsdWVzLlJEYXRhIikpCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKHNjYXJfY29yZV9yZWwpKQpzYXZlKHNhbXBfZGF0YSxmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLlJEYXRhIikpCiN3cml0ZS50YWJsZShzYW1wX2RhdGEgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLnR4dCIpLCBzZXAgPSAiXHQiLCBxdW90ZSA9IEYpCgpodWxsIDwtIGNiaW5kKHBjb2FfY29vcmQsIHNhbXBfZGF0YSkKaHVsbCRnZW9tb3JwaG8gPC0gc3RyX3JlcGxhY2VfYWxsKGh1bGwkZ2VvbW9ycGhvLCBjKCJtYWNyb2FsZ2FsIj0gIk0iICwgImNvcmFsIj0iQyIpKQoKIyBXaGF0IGlzIHRoZSBwZXJjZW50YWdlIG9mIHRoZSBleHBsaWNhdGl2ZSB2YXJpYW5jZT8gCnBhc3RlKCJBeGlzIDEgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKSkgCnBhc3RlKCJBeGlzIDIgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKSkgCnBhc3RlKCJBeGlzIDMgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzNdKSkKcGFzdGUoIkF4aXMgNCA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbNF0pKQoKcGNvYV9zY2FyaWRhZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9wb2ludChkYXRhID0gaHVsbCwgYWVzKHg9QXhpcy4xLCB5PUF4aXMuMiwgY29sb3IgPSB0YXgxLCBzaGFwZSA9IHNpdGUpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDgpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNToxOSkpKwogIHhsYWIocGFzdGUoIlBDbzEgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0qMTAwLCAxKSwgIiUpIikpICsKICB5bGFiKHBhc3RlKCJQQ28yICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSksICIlKSIpKSAgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLCBmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeC1heGlzIGxhYmVscwogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwICwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHktYXhpcyBsYWJlbHMKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1ham9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWlub3ItZ3JpZCBsYWJlbHMKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpKSsKICBsYWJzKGNvbG91ciA9ICJSZWVmIiwgc2hhcGUgPSAiU2l0ZSIpCnBjb2Ffc2NhcmlkYWUKYGBgCgpXZSB3aWxsIHRlc3QgdGhlIGVmZmVjdCBvZiB0aGUgdGF4b25vbWljYWwgbGV2ZWxzIChnZW51cyBhbmQgc3BlY2llcykKCmBgYHtyIHBlcm1hbm92YSBzY2FyMSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQphZG9uaXMobWF0cml4IH4gdGF4MSxkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gZ2VudXMsIGRhdGEgPSBzYW1wX2RhdGEpCmBgYAoKQmVjYXVzZSB0aGVyZSBpcyBhIGhpZ2ggdGF4b25vbWljIGVmZmVjdCwgd2Ugd2lsbCAiZnJlZXplIiB0aGUgZ2VudXMgZWZmZWN0IHRvIHRlc3QgdGhlIGVudmlyb25tZW50YWwgZWZmZWN0IChtZWFuaW5nIHRoYXQgd2UgdGVzdCB0aGUgc3Vic3RyYXRlLCBnZW9tb3JwaG8gYW5kIHNpdGUgZWZmZWN0IGluc2lkZSBlYWNoIGdlbnVzKS4gRXZlbiBzcGVjaWVzIGhhdmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgY29yZSBtaWNyb2JpYWwgY29tcG9zaXRpb24sIFdlIGNvdWxkbid0IHRlc3QgaW5zaWRlIHNwZWNpZXMgbGV2ZWwgYmVjYXVzZSB3ZSBtYW55IHNwZWNpZXMgd2VyZSBvbmx5IHJlcHJlc2VudGVkIGJ5IG9uZSBpbmRpdmlkdWFsLgoKYGBge3IgcGVybWFub3ZhIHNjYXIyLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmFkb25pcyhtYXRyaXggfiBnZW51cy90YXgxLCBzdHJhdGEgPSBzYW1wX2RhdGEkZ2VudXMsIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhtYXRyaXggfiBnZW51cy9zdWJzdHJhdCwgc3RyYXRhID0gc2FtcF9kYXRhJGdlbnVzLCBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gZ2VudXMvc2l0ZSwgc3RyYXRhID0gc2FtcF9kYXRhJGdlbnVzLCBkYXRhID0gc2FtcF9kYXRhKQpgYGAKCiMjIyMgKlNjYXJ1cyBnaG9iYmFuKgpGaW5hbGx5LCB0aGUgb25seSBoZXJiaXZvcm91cyBzcGVjaWVzIHdoaWNoIHdhcyBpbiBib3RoIHR5cGUgb2YgcmVlZnMgd2FzIHRoZSBTY2FydXMgZ2hvYmJhbiwgd2hvIGVhdHMgdGhlIGVwaWxpdGhpYyBwYXJ0IG9mIHRoZSBjb3JhbCwgc2VhcmNoaW5nIGZvciBjcnVzdGFsb3NlIGNhbGNhcm91cyBhbGdhZS4gCgpgYGB7ciBTQ0cgd2QsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiB9CmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL1NoaWZ0L1NDRy8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKU0NHIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXQsIHRheDEgPT0gIlNjYXJ1cyBnaG9iYmFuIikKU0NHIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhTQ0dAb3R1X3RhYmxlKT4wKSksIFNDRykKc2F2ZShTQ0csIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJTQ0cuUkRhdGEiKSkKU0NHcmZmIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoU0NHKSA+PSBtaW4oc2FtcGxlX3N1bXMoU0NHKSksIFNDRykKU0NHcmZmIDwtIHJhcmVmeV9ldmVuX2RlcHRoKFNDR3JmZiwgc2FtcGxlLnNpemUgPSBtaW4oc2FtcGxlX3N1bXMoU0NHKSkpCnNhdmUoU0NHcmZmLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiU0NHcmZmX3BzLlJEYXRhIikpCmNvcmVfU0NHIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgdGF4MSA9PSAiU2NhcnVzIGdob2JiYW4iKQpjb3JlX1NDRyA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoY29yZV9TQ0dAb3R1X3RhYmxlKT4wKSksIGNvcmVfU0NHKQpzYXZlKGNvcmVfU0NHLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9TQ0cuUkRhdGEiKSkKYGBgCgojIyMjIyBBbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkKYGBge3IgYWxwaGEgU0NHLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0gImNlbnRlciJ9CmJveDEgPSBwbG90X3JpY2huZXNzKFNDR3JmZiAsIG1lYXN1cmVzID0gYygiT2JzZXJ2ZWQiLCJTaGFubm9uIikgLCBjb2xvciA9ICJnZW9tb3JwaG8iKQojIF9fX18gU2hhbm5vbiBpbmRleCAoRU5TKQpib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlID0gZXhwKGJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUpCmxldmVscyhib3gxJGRhdGEkdmFyaWFibGUpPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpsZXZlbHMoYm94MSRkYXRhJGdlb21vcnBobykgPSBjKCJDIiAsICJNIikKCmxpYnJhcnkoZ2dzaWduaWYpCmxpYnJhcnkoZ2dwbG90MikKcGFsZXR0ZSA9IGMoImRhcmtibHVlIiwiZGFya3JlZCIpCnNleV9TQ0dfYWxwaGFfZGl2PSAgZ2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyNCwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIAogICAgICAgICAgICAgIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLCB0ZXh0c2l6ZT01LCBjb2xvcj0iYmxhY2siLCBmYW1pbHkgPSAic2VyaWYiKQoKc2V5X1NDR19hbHBoYV9kaXYKCk1XLm9icyA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXSkKTVcub2JzID0gY2JpbmQoTVcub2JzJHN0YXRpc3RpYywgTVcub2JzJHAudmFsdWUpCiMgX19fX19fX19fX19fIFNoYW5ub24gbnVtYmVyIE1XIApNVy5zaGFubm9uID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSkKTVcuc2hhbm5vbiA9Y2JpbmQoTVcuc2hhbm5vbiRzdGF0aXN0aWMsIE1XLnNoYW5ub24kcC52YWx1ZSkKIyBfX19fX19fX19fX18gQWxsIGNvbXB1dGVkIApNVy50ZXN0IDwtIHJiaW5kKE1XLm9icywgTVcuc2hhbm5vbikKcm93bmFtZXMoTVcudGVzdCkgPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpjb2xuYW1lcyhNVy50ZXN0KSA9IGMoJ1cgc3RhdCcgLCAncC12YWx1ZScpCk1XLnRlc3QKYGBgCgpgYGB7ciBiZXRhIFNDRywgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ICJjZW50ZXIifQpjb3JlX1NDR19yZWwgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoY29yZV9TQ0csIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkgKQpzYXZlKGNvcmVfU0NHX3JlbCAsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX1NDR19yZWwuUkRhdGEiKSkKIyBfX19fXyBQQ09BIGNvZGEgJiBwZXJtYW5vdmEgLS0tLS0tCm1hdHJpeCA8LSB2ZWdkaXN0KGNvcmVfU0NHX3JlbEBvdHVfdGFibGUsIG1ldGhvZCA9ICJicmF5IikKc2F2ZShtYXRyaXgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiZXRhX21hdHJpY2VzLlJEYXRhIikpCnBjb2Euc3ViIDwtIHBjb2EobWF0cml4KQpzYXZlKHBjb2Euc3ViLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicGNvYS52YWx1ZXMuUkRhdGEiKSkKCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKGNvcmVfU0NHX3JlbCkpCnNhdmUoc2FtcF9kYXRhLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEuUkRhdGEiKSkKI3dyaXRlLnRhYmxlKHNhbXBfZGF0YSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNhbXBfZGF0YS50eHQiKSwgc2VwPSAiXHQiLCBxdW90ZT0gRikKaHVsbCA8LSBjYmluZChwY29hX2Nvb3JkLCBzYW1wX2RhdGEpCmh1bGwkZ2VvbW9ycGhvIDwtIHN0cl9yZXBsYWNlX2FsbChodWxsJGdlb21vcnBobywgYygibWFjcm9hbGdhbCI9ICJNIiAsICJjb3JhbCI9IkMiKSkKCiMgV2hhdCBpcyB0aGUgcGVyY2VudGFnZSBvZiB0aGUgZXhwbGljYXRpdmUgdmFyaWFuY2U/IApwYXN0ZSgiQXhpcyAxIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSkpIApwYXN0ZSgiQXhpcyAyIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSkpIApwYXN0ZSgiQXhpcyAzIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1szXSkpCnBhc3RlKCJBeGlzIDQgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzRdKSkKCnBjb2FfU0NHIDwtIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBodWxsLCBhZXMoeD1BeGlzLjEsIHk9QXhpcy4yLCBjb2xvciA9IGdlb21vcnBobyksIGFscGhhID0gMC43LCBzaXplID0gOCwgc2hhcGUgPSAxNikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJEYXJrYmx1ZSIsIkRhcmtyZWQiKSkrCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAgLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpKwogIGxhYnMoY29sb3VyID0gIlJlZWYiKQpwY29hX1NDRwpgYGAKCldlIHRlc3QgdGhlIGVmZmVjdCBvZiB0aGUgcmVlZiBhdCBob3N0IGxldmVsLiAKCmBgYHtyIHBlcm1hbm92YTEgU0NHICAsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGIH0KYWRvbmlzKG1hdHJpeCB+IGdlb21vcnBobywgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCgpFdmVuIGlmIHdlIGNhbid0IHRlc3QgdGhlIGVmZmVjdCBvZiB0aGUgcmVlZiBvbiB0aGUgb3RoZXIgaGVyYml2b3JlcyBmYW1pbHksIHdlIGNhbiB0ZXN0IHRoZSBzaXRlLCBpc2xhbmQgYW5kIHN1YnN0cmF0IGVmZmVjdCBvbiB0aGUgU2lnYW5pZGFlLiAKCiMjIyMgU2lnYW5pZGFlIGZhbWlseQojIyMjIyBCZXRhIGRpdmVyc2l0eQpgYGB7ciBzaWdhbmlkYWUgd2QsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRn0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL1NoaWZ0L1NpZ2FuaWRhZS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKc2lnYW5pZGFlX3BzIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXQsIGZhbWlseSA9PSAiU2lnYW5pZGFlIikKc2lnYW5pZGFlX3BzIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhzaWdhbmlkYWVfcHNAb3R1X3RhYmxlKT4wKSksIHNpZ2FuaWRhZV9wcykKc2F2ZShzaWdhbmlkYWVfcHMsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzaWdhbmlkYWVfcHMuUkRhdGEiKSkKc2lnYW5pZGFlcmZmIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoc2lnYW5pZGFlX3BzKSA+PSBtaW4oc2FtcGxlX3N1bXMoc2lnYW5pZGFlX3BzKSkgLCBzaWdhbmlkYWVfcHMpCnNpZ2FuaWRhZXJmZiA8LSByYXJlZnlfZXZlbl9kZXB0aChzaWdhbmlkYWVfcHMgLG1pbihzYW1wbGVfc3VtcyhzaWdhbmlkYWVfcHMpKSkKc2F2ZShzaWdhbmlkYWVyZmYgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2lnYW5pZGFlcmZmLlJEYXRhIikpCnNpZ19jb3JlIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgZmFtaWx5ID09ICJTaWdhbmlkYWUiKQpzaWdfY29yZSA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoc2lnX2NvcmVAb3R1X3RhYmxlKT4wKSksIHNpZ19jb3JlKQpzYXZlKHNpZ19jb3JlLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2lnX2NvcmUuUkRhdGEiKSkKCmBgYAoKYGBge3IgYmV0YSBkaXYgc2lnYW5pZGFlLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0Kc2lnX2NvcmVfcmVsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKHNpZ19jb3JlLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpICkKc2F2ZShzaWdfY29yZV9yZWwgICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNpZ19jb3JlX3JlbC5SRGF0YSIpKQoKbWF0cml4IDwtIHZlZ2Rpc3Qoc2lnX2NvcmVfcmVsQG90dV90YWJsZSwgbWV0aG9kID0gImJyYXkiKQpzYXZlKG1hdHJpeCwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImJldGFfbWF0cmljZXMuUkRhdGEiKSkKcGNvYS5zdWIgPC0gcGNvYShtYXRyaXgpCnNhdmUocGNvYS5zdWIsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJwY29hLnZhbHVlcy5SRGF0YSIpKQojIENvbnRydWN0aW9uIG9mIHRoZSB0YWJsZSBmb3IgZ3JhcGhpYyAKcGNvYV9jb29yZCA8LSBwY29hLnN1YiR2ZWN0b3JzWywxOjNdCiMgX19fX18gUENPQSBQbG90LS0tLS0KbGlicmFyeShzdHJpbmdyKQpzYW1wX2RhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShzaWdfY29yZV9yZWwpKQpzYXZlKHNhbXBfZGF0YSxmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLlJEYXRhIikpCiN3cml0ZS50YWJsZShzYW1wX2RhdGEsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEudHh0IiksIHF1b3RlID0gRiwgc2VwID0gIlx0IikKaHVsbCA8LSBjYmluZChwY29hX2Nvb3JkLCBzYW1wX2RhdGEpCgojIFdoYXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGV4cGxpY2F0aXZlIHZhcmlhbmNlPyAKcGFzdGUoIkF4aXMgMSA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0pKSAKcGFzdGUoIkF4aXMgMiA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0pKSAKcGFzdGUoIkF4aXMgMyA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbM10pKQpwYXN0ZSgiQXhpcyA0IDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1s0XSkpCgpwY29hX3NpZyA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9wb2ludChkYXRhID0gaHVsbCwgYWVzKHg9QXhpcy4xLCB5PUF4aXMuMiwgY29sb3IgPSB0YXgxLCBzaGFwZSA9IHNpdGUpLGFscGhhID0gMC43LCBzaXplID0gOCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE4LDE1LDE2LDE3KSkrCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAgLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpKwogIGxhYnMoY29sb3VyID0gIlNwZWNpZXMiLCBzaGFwZSA9ICAiU2l0ZSIpCnBjb2Ffc2lnCmBgYAoKYGBge3IgcGVybWFub3ZhMSBzaWcsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGIH0KYWRvbmlzKG1hdHJpeCB+IHRheDEsZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IGlzbGFuZCwgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IHNpdGUsIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhtYXRyaXggfiBzdWJzdHJhdCwgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCgojIyMjICoqQ2Fybml2b3JlcyoqCiMjIyMgQ2Fybml2b3JvdXMgY29tbXVuaXR5CgpOb3cgbGV0J3Mgc2VlIHRoZSBpbmZsdWVuY2Ugb2YgdGhlIHNoaWZ0IG9uIHRoZSBjYXJuaXZvcmVzIHdoaWNoIHdlcmUgbW9yZSB1YmlxdWl0b3VzIGJldHdlZW4gc2l0ZXMgYW5kIHJlZWYgY29uZGl0aW9ucy4gCgpgYGB7ciBjYXJuaXZvcmVzIHdkLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvRmlzaC9TaGlmdC9DYXJuaXZvcmVzLyIpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFQpCmBgYApXZSBuZWVkIHRvIHN1YnNldCBmcm9tIHRoZSBgc2V5X2d1dGAgcGh5bG9zZXEgb2JqZWN0IHRoZSBjYXJuaXZvcm91cyBmaXNoZXMuIAoKYGBge3IgY2FybiBwaHlzZXEgY3JlYXRpb24gLGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiB9CmNhcm5fcHMgPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dCwgZGlldDMgPT0gIkNhcm5pdm9yb3VzIikKY2Fybl9wcyA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoY2Fybl9wc0BvdHVfdGFibGUpPjApKSwgY2Fybl9wcykKc2F2ZShjYXJuX3BzLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY2Fybl9wcy5SRGF0YSIpKQpyZmZfY2FybiA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKGNhcm5fcHMpID49IG1pbihzYW1wbGVfc3VtcyhjYXJuX3BzKSkgLCBjYXJuX3BzKQpyZmZfY2FybiA8LSByYXJlZnlfZXZlbl9kZXB0aChjYXJuX3BzICxtaW4oc2FtcGxlX3N1bXMoY2Fybl9wcykpKQpzYXZlKHJmZl9jYXJuICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInJmZl9jYXJuLlJEYXRhIikpCmNhcm5fY29yZSA8LSBzdWJzZXRfc2FtcGxlcyhzZXlfZ3V0X2NvcmUsIGRpZXQzID09ICJDYXJuaXZvcm91cyIpCmNhcm5fY29yZSA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoY2Fybl9jb3JlQG90dV90YWJsZSk+MCkpLCBjYXJuX2NvcmUpCnNhdmUoY2Fybl9jb3JlLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY2Fybl9jb3JlLlJEYXRhIikpCmBgYAoKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CgpgYGB7ciBhbHBoYSBiZXRhIGNhcm4sIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQpib3gxID0gcGxvdF9yaWNobmVzcyhyZmZfY2FybiAsIG1lYXN1cmVzID0gYygiT2JzZXJ2ZWQiLCJTaGFubm9uIikgLCBjb2xvciA9ICJnZW9tb3JwaG8iKQojIF9fX18gU2hhbm5vbiBpbmRleCAoRU5TKQpib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlID0gZXhwKGJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUpCmxldmVscyhib3gxJGRhdGEkdmFyaWFibGUpPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpsZXZlbHMoYm94MSRkYXRhJGdlb21vcnBobykgPSBjKCJDIiAsICJNIikKCmxpYnJhcnkoZ2dzaWduaWYpCmxpYnJhcnkoZ2dwbG90MikKcGFsZXR0ZSA9IGMoImRhcmtibHVlIiwiZGFya3JlZCIpCgpzZXlfY2Fybl9hbHBoYV9kaXY9ICBnZ3Bsb3QoYm94MSRkYXRhLCBhZXMoeCA9IGZhY3RvcihnZW9tb3JwaG8pICwgeSA9IHZhbHVlLCBjb2xvciA9IGZhY3RvcihnZW9tb3JwaG8pKSkgKyAKICBnZW9tX2ppdHRlcihwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4yMCksIGFscGhhID0gMC41LCBzaXplID0gMykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPSBwYWxldHRlKSArIHRoZW1lX2J3KCkrCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuMSwgb3V0bGllci5jb2xvdXIgPSBOQSkgKyAKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAxNCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDI0LCBhbmdsZSA9IDApLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDIwLCBhbmdsZSA9IDApLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBmYW1pbHkgPSAic2VyaWYiKSkgKyAKICBmYWNldF93cmFwKCB+IHZhcmlhYmxlLCBucm93PTEsIG5jb2w9NSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoIkMiLCAiTSIpKSwgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRleHRzaXplPTUsIGNvbG9yPSJibGFjayIsIGZhbWlseSA9ICJzZXJpZiIpCgpzZXlfY2Fybl9hbHBoYV9kaXYgCgojIF9fX18gVGVzdCBNVyAtLS0tCmxpYnJhcnkocGdpcm1lc3MpCiMgRG9lcyBleGlzdCBkaWZmZXJlbmNlcyBpbiBkaXZlcnNpdHkgYmV0d2VlbiB0eXBlcyBvZiBob3N0PyAKIyBfX19fX19fX19fX18gT2JzZXJ2ZWQgcmljaG5lc3MgTVcgCk1XLm9icyA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXSkKTVcub2JzID0gY2JpbmQoTVcub2JzJHN0YXRpc3RpYywgTVcub2JzJHAudmFsdWUpCiMgX19fX19fX19fX19fIFNoYW5ub24gbnVtYmVyIE1XIApNVy5zaGFubm9uID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSkKTVcuc2hhbm5vbiA9Y2JpbmQoTVcuc2hhbm5vbiRzdGF0aXN0aWMsIE1XLnNoYW5ub24kcC52YWx1ZSkKIyBfX19fX19fX19fX18gQWxsIGNvbXB1dGVkIApNVy50ZXN0IDwtIHJiaW5kKE1XLm9icywgTVcuc2hhbm5vbikKcm93bmFtZXMoTVcudGVzdCkgPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpjb2xuYW1lcyhNVy50ZXN0KSA9IGMoJ1cgc3RhdCcgLCAncC12YWx1ZScpCk1XLnRlc3QKYGBgCgpgYGB7ciBiZXRhIGNhcm4gLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KY29yZV9jYXJuX3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhjYXJuX2NvcmUsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkgKQpzYXZlKGNvcmVfY2Fybl9yZWwgICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImNvcmVfY2Fybl9yZWwuUkRhdGEiKSkKCm1hdHJpeCA8LSB2ZWdkaXN0KGNvcmVfY2Fybl9yZWxAb3R1X3RhYmxlLCBtZXRob2QgPSAiYnJheSIpCnNhdmUobWF0cml4LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiYmV0YV9tYXRyaWNlcy5SRGF0YSIpKQpwY29hLnN1YiA8LSBwY29hKG1hdHJpeCkKc2F2ZShwY29hLnN1YiwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBjb2EudmFsdWVzLlJEYXRhIikpCgojIENvbnRydWN0aW9uIG9mIHRoZSB0YWJsZSBmb3IgZ3JhcGhpYyAKcGNvYV9jb29yZCA8LSBwY29hLnN1YiR2ZWN0b3JzWywxOjNdCiMgX19fX18gUENPQSBQbG90LS0tLS0KbGlicmFyeShzdHJpbmdyKQpzYW1wX2RhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShjb3JlX2Nhcm5fcmVsKSkKc2F2ZShzYW1wX2RhdGEsZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNhbXBfZGF0YS5SRGF0YSIpKQojd3JpdGUudGFibGUoc2FtcF9kYXRhLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLnR4dCIpLCBxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCmh1bGwgPC0gY2JpbmQocGNvYV9jb29yZCwgc2FtcF9kYXRhKQpodWxsJGdlb21vcnBobyA8LSBzdHJfcmVwbGFjZV9hbGwoaHVsbCRnZW9tb3JwaG8sIGMoIm1hY3JvYWxnYWwiPSAiTSIgLCAiY29yYWwiPSJDIikpCgojIFdoYXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGV4cGxpY2F0aXZlIHZhcmlhbmNlPyAKcGFzdGUoIkF4aXMgMSA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0pKSAKcGFzdGUoIkF4aXMgMiA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0pKSAKcGFzdGUoIkF4aXMgMyA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbM10pKQpwYXN0ZSgiQXhpcyA0IDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1s0XSkpCgpwY29hX2Nhcm4gPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGh1bGwsIGFlcyh4PUF4aXMuMSwgeT1BeGlzLjIsIGNvbG9yID0gZ2VvbW9ycGhvLCBzaGFwZSA9IGZhbWlseSksIGFscGhhID0gMC43LCBzaXplID0gOCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID1jKDE1OjE4LCA4KSkrCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAgLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpKwogIGxhYnMoY29sb3VyID0gIlJlZWYiLCBzaGFwZT0gIkZhbWlseSIpCnBjb2FfY2FybgoKYGBgCgpXZSB0ZXN0ZWQgZmlyc3QgdGhlIGluZmx1ZW5jZSBvZiB0aGUgZW52aXJvbm1lbnQKYGBge3IgcGVybWFub3ZhMSBjYXJuLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYgfQphZG9uaXMobWF0cml4IH4gaXNsYW5kLCAgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IGdlb21vcnBobywgIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhtYXRyaXggfiBzaXRlLCAgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IHN1YnN0cmF0LCAgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCgpBbmQgdGhlbiB0aGUgdGF4b25vbWljIGVmZmVjdAoKYGBge3IgcGVybWFub3ZhMiBjYXJuLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CmFkb25pcyhtYXRyaXggfiBmYW1pbHksICBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gZmFtaWx5L2dlbnVzL3RheDEgLCAgZGF0YSA9c2FtcF9kYXRhKQpgYGAKCiMjIyMgTHV0amFuaWRhZSBmYW1pbHkKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CmBgYHtyIGx1dGphbmlkYWUgd2QsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0Zpc2gvU2hpZnQvTHV0amFuaWRhZS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKbHV0al9wcyA8LSBzdWJzZXRfc2FtcGxlcyhzZXlfZ3V0LCBmYW1pbHkgPT0gIkx1dGphbmlkYWUiKQpsdXRqX3BzIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhsdXRqX3BzQG90dV90YWJsZSk+MCkpLCBsdXRqX3BzKQpzYXZlKGx1dGpfcHMsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJsdXRqX3BzLlJEYXRhIikpCnJmZl9sdXRqIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMobHV0al9wcykgPj0gbWluKHNhbXBsZV9zdW1zKGx1dGpfcHMpKSAsIGx1dGpfcHMpCnJmZl9sdXRqIDwtIHJhcmVmeV9ldmVuX2RlcHRoKGx1dGpfcHMgLG1pbihzYW1wbGVfc3VtcyhsdXRqX3BzKSkpCnNhdmUocmZmX2x1dGogLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicmZmX2x1dGouUkRhdGEiKSkKY29yZV9sdXRqIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgZmFtaWx5ID09ICJMdXRqYW5pZGFlIikKY29yZV9sdXRqIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3Vtcyhjb3JlX2x1dGpAb3R1X3RhYmxlKT4wKSksIGNvcmVfbHV0aikKc2F2ZShjb3JlX2x1dGosIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX2x1dGouUkRhdGEiKSkKCiMgX18gQWxwaGEgZGl2ZXJzaXR5IC0tLS0KYm94MSA9IHBsb3RfcmljaG5lc3MocmZmX2x1dGogLCBtZWFzdXJlcyA9IGMoIk9ic2VydmVkIiwiU2hhbm5vbiIpICwgY29sb3IgPSAiZ2VvbW9ycGhvIikKIyBfX19fIFNoYW5ub24gaW5kZXggKEVOUykKYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSA9IGV4cChib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlKQpsZXZlbHMoYm94MSRkYXRhJHZhcmlhYmxlKT0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKbGV2ZWxzKGJveDEkZGF0YSRnZW9tb3JwaG8pID0gYygiQyIgLCAiTSIpCgpsaWJyYXJ5KGdnc2lnbmlmKQpsaWJyYXJ5KGdncGxvdDIpCnBhbGV0dGUgPSBjKCJkYXJrYmx1ZSIsImRhcmtyZWQiKQoKc2V5X2x1dGpfYWxwaGFfZGl2PSAgZ2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyNCwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLCB0ZXh0c2l6ZT01LCBjb2xvcj0iYmxhY2siLCBmYW1pbHkgPSAic2VyaWYiKQpzZXlfbHV0al9hbHBoYV9kaXYgCgojIF9fX18gVGVzdCBNVyAtLS0tCmxpYnJhcnkocGdpcm1lc3MpCiMgRG9lcyBleGlzdCBkaWZmZXJlbmNlcyBpbiBkaXZlcnNpdHkgYmV0d2VlbiB0eXBlcyBvZiBob3N0PyAKIyBfX19fX19fX19fX18gT2JzZXJ2ZWQgcmljaG5lc3MgTVcgCk1XLm9icyA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXSkKTVcub2JzID0gY2JpbmQoTVcub2JzJHN0YXRpc3RpYywgTVcub2JzJHAudmFsdWUpCiMgX19fX19fX19fX19fIFNoYW5ub24gbnVtYmVyIE1XIApNVy5zaGFubm9uID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSkKTVcuc2hhbm5vbiA9Y2JpbmQoTVcuc2hhbm5vbiRzdGF0aXN0aWMsIE1XLnNoYW5ub24kcC52YWx1ZSkKIyBfX19fX19fX19fX18gQWxsIGNvbXB1dGVkIApNVy50ZXN0IDwtIHJiaW5kKE1XLm9icywgTVcuc2hhbm5vbikKcm93bmFtZXMoTVcudGVzdCkgPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpjb2xuYW1lcyhNVy50ZXN0KSA9IGMoJ1cgc3RhdCcgLCAncC12YWx1ZScpCk1XLnRlc3QKCmBgYAoKYGBge3IgQmV0YS1kaXYgTHV0amFuaWRhZSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CmNvcmVfbHV0al9yZWwgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoY29yZV9sdXRqLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpICkKc2F2ZShjb3JlX2x1dGpfcmVsICAsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX2x1dGpfcmVsLlJEYXRhIikpCiMgX19fX18gUENPQSBjb2RhICYgcGVybWFub3ZhIC0tLS0tLQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGFwZSkKbWF0cml4IDwtIHZlZ2Rpc3QoY29yZV9sdXRqX3JlbEBvdHVfdGFibGUsIG1ldGhvZCA9ICJicmF5IikKc2F2ZShtYXRyaXgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiZXRhX21hdHJpY2VzLlJEYXRhIikpCnBjb2Euc3ViIDwtIHBjb2EobWF0cml4KQpzYXZlKHBjb2Euc3ViLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicGNvYS52YWx1ZXMuUkRhdGEiKSkKCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKGNvcmVfbHV0al9yZWwpKQpzYXZlKHNhbXBfZGF0YSxmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLlJEYXRhIikpCiN3cml0ZS50YWJsZShzYW1wX2RhdGEsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEudHh0IiksIHNlcCA9ICJcdCIsIHF1b3RlID0gRikKCmh1bGwgPC0gY2JpbmQocGNvYV9jb29yZCwgc2FtcF9kYXRhKQpodWxsJGdlb21vcnBobyA8LSBzdHJfcmVwbGFjZV9hbGwoaHVsbCRnZW9tb3JwaG8sIGMoIm1hY3JvYWxnYWwiPSAiTSIgLCAiY29yYWwiPSJDIikpCgojIFdoYXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGV4cGxpY2F0aXZlIHZhcmlhbmNlPyAKcGFzdGUoIkF4aXMgMSA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0pKSAKcGFzdGUoIkF4aXMgMiA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0pKSAKcGFzdGUoIkF4aXMgMyA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbM10pKQpwYXN0ZSgiQXhpcyA0IDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1s0XSkpCgpwY29hX2x1dGogPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGh1bGwsIGFlcyh4PUF4aXMuMSwgeT1BeGlzLjIsIGNvbG9yID0gZ2VvbW9ycGhvKSwgYWxwaGEgPSAwLjcsIHNpemUgPSA4LCBzaGFwZSA9IDE2KSArCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9IHBhbGV0dGUpKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLCBmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeC1heGlzIGxhYmVscwogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwICwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHktYXhpcyBsYWJlbHMKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1ham9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWlub3ItZ3JpZCBsYWJlbHMKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpKSsKICBsYWJzKGNvbG91ciA9ICJSZWVmIikKcGNvYV9sdXRqCmBgYAoKVGhlIHNhbXBsaW5nIHNpemUgZm9yIHRoZSBtZW1iZXJzIG9mIHRoZSBMdXRqYW5pZGFlIGZhbWlseSB3YXMgZW5vdWdoIHRvIHRlc3Qgc2V2ZXJhbCBwYXJhbWV0ZXJzIGFzIGVmZmVjdCBvZiBzcGVjaWVzLCBnZW51cywgZ2VvbW9ycGhvbG9neSBvZiB0aGUgcmVlZiwgc2l0ZSBhbmQgc3Vic3RyYXQuCgpgYGB7ciBwZXJtYW5vdmExIGx1dGosIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRn0KYWRvbmlzKG1hdHJpeCB+IHRheDEsICBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gZ2VudXMsICBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gZ2VvbW9ycGhvLCAgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IHNpdGUsICBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gc3Vic3RyYXQsICBkYXRhID0gc2FtcF9kYXRhKQoKYmV0YV9yZWVmIDwtIGJldGFkaXNwZXIobWF0cml4LCBzYW1wX2RhdGEkdGF4MSkKcGVybXV0ZXN0KGJldGFfcmVlZikKYGBgCgpJbiB0aGlzIGZhbWlseSwgd2UgY291bGQgdGVzdCBhdCBob3N0IGxldmVsIHRoZSBlZmZlY3Qgb24gdGhlIHNwZWNpZXMgKkFwcmlvbiB2aXJlc2NlbnMqLgoKIyMjIyAqQXByaW9uIHZpcmVzY2VucyoKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CgpgYGB7ciBBUFYgd2QsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiB9CmRpcl9kYXRhX2NsZWFuaW5nIDwtIHBhc3RlMChwYXRoLCAiL2FuYWx5c2VzLzA0X2RhdGFfY2xlYW5pbmcvRmlzaC9TaGlmdC9BUFYvIikKZGlyLmNyZWF0ZShkaXJfZGF0YV9jbGVhbmluZywgcmVjdXJzaXZlID0gVCkKCkFQViA8LSBzdWJzZXRfc2FtcGxlcyhzZXlfZ3V0LCB0YXgxID09ICJBcHJpb24gdmlyZXNjZW5zIikKQVBWIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhBUFZAb3R1X3RhYmxlKT4wKSksIEFQVikKc2F2ZShBUFYsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJBUFYuUkRhdGEiKSkKQVBWcmZmIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoQVBWKSA+PSBtaW4oc2FtcGxlX3N1bXMoQVBWKSksIEFQVikKQVBWcmZmIDwtIHJhcmVmeV9ldmVuX2RlcHRoKEFQVnJmZiwgc2FtcGxlLnNpemUgPSBtaW4oc2FtcGxlX3N1bXMoQVBWKSkpCnNhdmUoQVBWcmZmLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiQVBWcmZmX3BzLlJEYXRhIikpCmNvcmVfQVBWIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgdGF4MSA9PSAiQXByaW9uIHZpcmVzY2VucyIpCmNvcmVfQVBWIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3Vtcyhjb3JlX0FQVkBvdHVfdGFibGUpPjApKSxjb3JlX0FQVikKc2F2ZShjb3JlX0FQViwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImNvcmVfQVBWLlJEYXRhIikpCmBgYAoKYGBge3IgYWxwaGEgZGl2ZXJzaXR5IEFQViwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CmJveDEgPSBwbG90X3JpY2huZXNzKEFQVnJmZiAsIG1lYXN1cmVzID0gYygiT2JzZXJ2ZWQiLCJTaGFubm9uIikgLCBjb2xvciA9ICJnZW9tb3JwaG8iKQojIF9fX18gU2hhbm5vbiBpbmRleCAoRU5TKQpib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlID0gZXhwKGJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUpCmxldmVscyhib3gxJGRhdGEkdmFyaWFibGUpPSBjKCJPYnNlcnZlZCByaWNobmVzcyIsIlNoYW5ub24gKEVOUykiKQpsZXZlbHMoYm94MSRkYXRhJGdlb21vcnBobykgPSBjKCJDIiAsICJNIikKCmxpYnJhcnkoZ2dzaWduaWYpCmxpYnJhcnkoZ2dwbG90MikKcGFsZXR0ZSA9IGMoImRhcmtibHVlIiwiZGFya3JlZCIpCgpzZXlfQVBWX2FscGhhX2Rpdj0gIGdncGxvdChib3gxJGRhdGEsIGFlcyh4ID0gZmFjdG9yKGdlb21vcnBobykgLCB5ID0gdmFsdWUsIGNvbG9yID0gZmFjdG9yKGdlb21vcnBobykpKSArIAogIGdlb21faml0dGVyKHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gLjIwKSwgYWxwaGEgPSAwLjUsIHNpemUgPSAzKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9IHBhbGV0dGUpICsgdGhlbWVfYncoKSsKICBnZW9tX2JveHBsb3QoYWxwaGE9MC4xLCBvdXRsaWVyLmNvbG91ciA9IE5BKSArIAogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDE0KSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMjAsIGFuZ2xlID0gMCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMjAsIGFuZ2xlID0gMCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTUsIGZhbWlseSA9ICJzZXJpZiIpKSArIAogIGZhY2V0X3dyYXAoIH4gdmFyaWFibGUsIG5yb3c9MSwgbmNvbD01LCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX3NpZ25pZihjb21wYXJpc29ucyA9IGxpc3QoYygiQyIsICJNIikpLCBtYXBfc2lnbmlmX2xldmVsID0gVFJVRSwgdGV4dHNpemU9OCwgY29sb3I9ImJsYWNrIiwgZmFtaWx5ID0gInNlcmlmIikKCnNleV9BUFZfYWxwaGFfZGl2IAoKIyBfX19fIFRlc3QgTVcgLS0tLQpsaWJyYXJ5KHBnaXJtZXNzKQojIERvZXMgZXhpc3QgZGlmZmVyZW5jZXMgaW4gZGl2ZXJzaXR5IGJldHdlZW4gdHlwZXMgb2YgaG9zdD8gCiMgX19fX19fX19fX19fIE9ic2VydmVkIHJpY2huZXNzIE1XIApNVy5vYnMgPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl0pCk1XLm9icyA9IGNiaW5kKE1XLm9icyRzdGF0aXN0aWMsIE1XLm9icyRwLnZhbHVlKQojIF9fX19fX19fX19fXyBTaGFubm9uIG51bWJlciBNVyAKTVcuc2hhbm5vbiA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl0pCk1XLnNoYW5ub24gPWNiaW5kKE1XLnNoYW5ub24kc3RhdGlzdGljLCBNVy5zaGFubm9uJHAudmFsdWUpCiMgX19fX19fX19fX19fIEFsbCBjb21wdXRlZCAKTVcudGVzdCA8LSByYmluZChNVy5vYnMsIE1XLnNoYW5ub24pCnJvd25hbWVzKE1XLnRlc3QpID0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKY29sbmFtZXMoTVcudGVzdCkgPSBjKCdXIHN0YXQnICwgJ3AtdmFsdWUnKQpNVy50ZXN0CmBgYAoKCiMjIyMgTGV0aHJpbmlkYWUKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CmBgYHtyIGxldGhyaW5pZGFlIHdkLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL1NoaWZ0L0xldGhyaW51cy8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKc2V5X2xldGggPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dCwgZmFtaWx5ID09ICJMZXRocmluaWRhZSIpCnNleV9sZXRoIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhzZXlfbGV0aEBvdHVfdGFibGUpPjApKSwgc2V5X2xldGgpCnNhdmUoc2V5X2xldGgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzZXlfbGV0aC5SRGF0YSIpKQpyZmZfbGV0aCA8LSBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKHNleV9sZXRoKSA+PSBtaW4oc2FtcGxlX3N1bXMoc2V5X2xldGgpKSAsIHNleV9sZXRoKQpyZmZfbGV0aCA8LSByYXJlZnlfZXZlbl9kZXB0aChyZmZfbGV0aCAsbWluKHNhbXBsZV9zdW1zKHJmZl9sZXRoKSkpCnNhdmUocmZmX2xldGggLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicmZmX2xldGguUkRhdGEiKSkKY29yZV9sZXRoIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgZ2VudXMgPT0gIkxldGhyaW51cyIpCmNvcmVfbGV0aCA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoY29yZV9sZXRoQG90dV90YWJsZSk+MCkpLGNvcmVfbGV0aCkKc2F2ZShjb3JlX2xldGgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX2xldGguUkRhdGEiKSkKYGBgCgpgYGB7ciBhbHBoYSBkaXYgbGV0aHJpbmlkYWUgLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KYm94MSA9IHBsb3RfcmljaG5lc3MocmZmX2xldGggLCBtZWFzdXJlcyA9IGMoIk9ic2VydmVkIiwiU2hhbm5vbiIpICwgY29sb3IgPSAiZ2VvbW9ycGhvIikKYm94MSRkYXRhCiMgX19fXyBTaGFubm9uIGluZGV4IChFTlMpCmJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUgPSBleHAoYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSkKbGV2ZWxzKGJveDEkZGF0YSR2YXJpYWJsZSk9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwiU2hhbm5vbiAoRU5TKSIpCmxldmVscyhib3gxJGRhdGEkZ2VvbW9ycGhvKSA9IGMoIkMiICwgIk0iKQoKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ3Bsb3QyKQpwYWxldHRlID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikKCnNleV9sZXRocl9hbHBoYV9kaXY9ICBnZ3Bsb3QoYm94MSRkYXRhLCBhZXMoeCA9IGZhY3RvcihnZW9tb3JwaG8pICwgeSA9IHZhbHVlLCBjb2xvciA9IGZhY3RvcihnZW9tb3JwaG8pKSkgKyAKICBnZW9tX2ppdHRlcihwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4yMCksIGFscGhhID0gMC41LCBzaXplID0gMykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPSBwYWxldHRlKSArIHRoZW1lX2J3KCkrCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuMSwgb3V0bGllci5jb2xvdXIgPSBOQSkgKyAKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAxNCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDI0LCBhbmdsZSA9IDApLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDIwLCBhbmdsZSA9IDApLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBmYW1pbHkgPSAic2VyaWYiKSkgKyAKICBmYWNldF93cmFwKCB+IHZhcmlhYmxlLCBucm93PTEsIG5jb2w9NSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoIkMiLCAiTSIpKSwgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRleHRzaXplPTUsIGNvbG9yPSJibGFjayIsIGZhbWlseSA9ICJzZXJpZiIpCgpzZXlfbGV0aHJfYWxwaGFfZGl2IAoKIyBfX19fIFRlc3QgTVcgLS0tLQpsaWJyYXJ5KHBnaXJtZXNzKQojIERvZXMgZXhpc3QgZGlmZmVyZW5jZXMgaW4gZGl2ZXJzaXR5IGJldHdlZW4gdHlwZXMgb2YgaG9zdD8gCiMgX19fX19fX19fX19fIE9ic2VydmVkIHJpY2huZXNzIE1XIApNVy5vYnMgPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl0pCk1XLm9icyA9IGNiaW5kKE1XLm9icyRzdGF0aXN0aWMsIE1XLm9icyRwLnZhbHVlKQojIF9fX19fX19fX19fXyBTaGFubm9uIG51bWJlciBNVyAKTVcuc2hhbm5vbiA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl0pCk1XLnNoYW5ub24gPWNiaW5kKE1XLnNoYW5ub24kc3RhdGlzdGljLCBNVy5zaGFubm9uJHAudmFsdWUpCiMgX19fX19fX19fX19fIEFsbCBjb21wdXRlZCAKTVcudGVzdCA8LSByYmluZChNVy5vYnMsIE1XLnNoYW5ub24pCnJvd25hbWVzKE1XLnRlc3QpID0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKY29sbmFtZXMoTVcudGVzdCkgPSBjKCdXIHN0YXQnICwgJ3AtdmFsdWUnKQpNVy50ZXN0CmBgYAoKCmBgYHtyIGJldGEgZGl2IGxldGhyaW5pZGFlLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KY29yZV9sZXRoX3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhjb3JlX2xldGgsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkgKQpzYXZlKGNvcmVfbGV0aF9yZWwgICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImNvcmVfbGV0aF9yZWwuUkRhdGEiKSkKIyBfX19fXyBQQ09BIGNvZGEgJiBwZXJtYW5vdmEgLS0tLS0tCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoYXBlKQptYXRyaXggPC0gdmVnZGlzdChjb3JlX2xldGhfcmVsQG90dV90YWJsZSwgbWV0aG9kID0gImJyYXkiKQpzYXZlKG1hdHJpeCwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImJldGFfbWF0cmljZXMuUkRhdGEiKSkKcGNvYS5zdWIgPC0gcGNvYShtYXRyaXgpCnNhdmUocGNvYS5zdWIsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJwY29hLnZhbHVlcy5SRGF0YSIpKQoKIyBDb250cnVjdGlvbiBvZiB0aGUgdGFibGUgZm9yIGdyYXBoaWMgCnBjb2FfY29vcmQgPC0gcGNvYS5zdWIkdmVjdG9yc1ssMTozXQojIF9fX19fIFBDT0EgUGxvdC0tLS0tCmxpYnJhcnkoc3RyaW5ncikKc2FtcF9kYXRhIDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEoY29yZV9sZXRoX3JlbCkpCnNhdmUoc2FtcF9kYXRhLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEuUkRhdGEiKSkKI3dyaXRlLnRhYmxlKHNhbXBfZGF0YSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNhbXBfZGF0YS50eHQiKSwgcXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKaHVsbCA8LSBjYmluZChwY29hX2Nvb3JkLCBzYW1wX2RhdGEpCmh1bGwkZ2VvbW9ycGhvIDwtIHN0cl9yZXBsYWNlX2FsbChodWxsJGdlb21vcnBobywgYygibWFjcm9hbGdhbCI9ICJNIiAsICJjb3JhbCI9IkMiKSkKCiMgV2hhdCBpcyB0aGUgcGVyY2VudGFnZSBvZiB0aGUgZXhwbGljYXRpdmUgdmFyaWFuY2U/IApwYXN0ZSgiQXhpcyAxIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSkpIApwYXN0ZSgiQXhpcyAyIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSkpIApwYXN0ZSgiQXhpcyAzIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1szXSkpCnBhc3RlKCJBeGlzIDQgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzRdKSkKCnBjb2FfbGV0aHIgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGh1bGwsIGFlcyh4PUF4aXMuMSwgeT1BeGlzLjIsIGNvbG9yID0gZ2VvbW9ycGhvKSwgYWxwaGEgPSAwLjcsIHNpemUgPSA4LCBzaGFwZSA9IDE2KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkRhcmtibHVlIiwiRGFya3JlZCIpKSsKICB4bGFiKHBhc3RlKCJQQ28xICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSksICIlKSIpKSArCiAgeWxhYihwYXN0ZSgiUENvMiAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSoxMDAsIDEpLCAiJSkiKSkgICsKICB0aGVtZV9idygpICsKICBjb29yZF9lcXVhbCgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCwgZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHgtYXhpcyBsYWJlbHMKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCAsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB5LWF4aXMgbGFiZWxzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtYWpvci1ncmlkIGxhYmVscwogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1pbm9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSkrCiAgbGFicyhjb2xvdXIgPSAiUmVlZiIpCnBjb2FfbGV0aHIKYGBgCgpgYGB7ciBwZXJtYW5vdmEgbGV0aHJpbmlkYWUsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CmFkb25pcyhtYXRyaXggfiB0YXgxICwgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IGlzbGFuZCwgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IGdlb21vcnBobywgZGF0YSA9IHNhbXBfZGF0YSkKYWRvbmlzKG1hdHJpeCB+IHN1YnN0cmF0LCBkYXRhID0gc2FtcF9kYXRhKQphZG9uaXMobWF0cml4IH4gc2l0ZSwgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCgpJbnNpZGUgdGhpcyBmYW1pbHksIHdlIGFyZSBhYmxlIHRvIHRlc3QgdHdvIGRpZmZlcmVudCBzcGVjaWVzIDogKkxldGhyaW51cyBtYWhzZW5hKiBhbmQgICpMZXRocmludXMgZW5pZ21hdGljdXMqLiAKCiMjIyMgKkxldGhyaW51cyBtYWhzZW5hKgojIyMjIyBBbHBoYSBhbmQgYmV0YSBkaXZlcnNpdHkKCmBgYHtyIHdkIExFTSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0Zpc2gvU2hpZnQvTEVNLyIpCmRpci5jcmVhdGUoZGlyX2RhdGFfY2xlYW5pbmcsIHJlY3Vyc2l2ZSA9IFQpCgpMRU0gPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dCwgdGF4MSA9PSAiTGV0aHJpbnVzIG1haHNlbmEiKQpMRU0gPC0gcHJ1bmVfdGF4YShuYW1lcyh3aGljaChjb2xTdW1zKExFTUBvdHVfdGFibGUpPjApKSwgTEVNKQpzYXZlKExFTSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgIkxFTS5SRGF0YSIpKQpMRU1yZmYgPC0gcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyhMRU0pID49IG1pbihzYW1wbGVfc3VtcyhMRU0pKSAsIExFTSkKTEVNcmZmIDwtIHJhcmVmeV9ldmVuX2RlcHRoKExFTXJmZiAsbWluKHNhbXBsZV9zdW1zKExFTXJmZikpKQpzYXZlKExFTXJmZiAsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMRU1yZmYuUkRhdGEiKSkKY29yZV9MRU0gPC0gc3Vic2V0X3NhbXBsZXMoc2V5X2d1dF9jb3JlLCB0YXgxID09ICJMZXRocmludXMgbWFoc2VuYSIpCmNvcmVfTEVNIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3Vtcyhjb3JlX0xFTUBvdHVfdGFibGUpPjApKSwgY29yZV9MRU0pCnNhdmUoY29yZV9MRU0sIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX0xFTS5SRGF0YSIpKQpgYGAKCmBgYHtyIGFscGhhIGRpdiBMRU0sIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQpib3gxID0gcGxvdF9yaWNobmVzcyhMRU1yZmYgLCBtZWFzdXJlcyA9IGMoIk9ic2VydmVkIiwiU2hhbm5vbiIpICwgY29sb3IgPSAiZ2VvbW9ycGhvIikKIyBfX19fIFNoYW5ub24gaW5kZXggKEVOUykKYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSA9IGV4cChib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlKQpsZXZlbHMoYm94MSRkYXRhJHZhcmlhYmxlKT0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKbGV2ZWxzKGJveDEkZGF0YSRnZW9tb3JwaG8pID0gYygiQyIgLCAiTSIpCgpsaWJyYXJ5KGdnc2lnbmlmKQpsaWJyYXJ5KGdncGxvdDIpCnBhbGV0dGUgPSBjKCJkYXJrYmx1ZSIsImRhcmtyZWQiKQoKc2V5X0xFTV9hbHBoYV9kaXY9ICBnZ3Bsb3QoYm94MSRkYXRhLCBhZXMoeCA9IGZhY3RvcihnZW9tb3JwaG8pICwgeSA9IHZhbHVlLCBjb2xvciA9IGZhY3RvcihnZW9tb3JwaG8pKSkgKyAKICBnZW9tX2ppdHRlcihwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IC4yMCksIGFscGhhID0gMC41LCBzaXplID0gMykgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPSBwYWxldHRlKSArIHRoZW1lX2J3KCkrCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuMSwgb3V0bGllci5jb2xvdXIgPSBOQSkgKyAKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAxNCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDI0LCBhbmdsZSA9IDApLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIsc2l6ZSA9IDIwLCBhbmdsZSA9IDApLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBmYW1pbHkgPSAic2VyaWYiKSkgKyAKICBmYWNldF93cmFwKCB+IHZhcmlhYmxlLCBucm93PTEsIG5jb2w9NSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoIkMiLCAiTSIpKSwgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRleHRzaXplPTUsIGNvbG9yPSJibGFjayIsIGZhbWlseSA9ICJzZXJpZiIpCgpzZXlfTEVNX2FscGhhX2RpdiAKIyBfX19fIFRlc3QgTVcgLS0tLQpsaWJyYXJ5KHBnaXJtZXNzKQojIERvZXMgZXhpc3QgZGlmZmVyZW5jZXMgaW4gZGl2ZXJzaXR5IGJldHdlZW4gdHlwZXMgb2YgaG9zdD8gCiMgX19fX19fX19fX19fIE9ic2VydmVkIHJpY2huZXNzIE1XIApNVy5vYnMgPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iT2JzZXJ2ZWQgcmljaG5lc3MiXX5ib3gxJGRhdGEkZ2VvbW9ycGhvW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl0pCk1XLm9icyA9IGNiaW5kKE1XLm9icyRzdGF0aXN0aWMsIE1XLm9icyRwLnZhbHVlKQojIF9fX19fX19fX19fXyBTaGFubm9uIG51bWJlciBNVyAKTVcuc2hhbm5vbiA9IHdpbGNveC50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl0pCk1XLnNoYW5ub24gPWNiaW5kKE1XLnNoYW5ub24kc3RhdGlzdGljLCBNVy5zaGFubm9uJHAudmFsdWUpCiMgX19fX19fX19fX19fIEFsbCBjb21wdXRlZCAKTVcudGVzdCA8LSByYmluZChNVy5vYnMsIE1XLnNoYW5ub24pCnJvd25hbWVzKE1XLnRlc3QpID0gYygiT2JzZXJ2ZWQgcmljaG5lc3MiLCJTaGFubm9uIChFTlMpIikKY29sbmFtZXMoTVcudGVzdCkgPSBjKCdXIHN0YXQnICwgJ3AtdmFsdWUnKQpNVy50ZXN0CmBgYAoKYGBge3IgYmV0YS1kaXYgTEVNLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KY29yZV9MRU1fcmVsIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGNvcmVfTEVNLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpICkKc2F2ZShjb3JlX0xFTV9yZWwgICwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImNvcmVfTEVNX3JlbC5SRGF0YSIpKQojIF9fX19fIFBDT0EgY29kYSAmIHBlcm1hbm92YSAtLS0tLS0KbGlicmFyeSh2ZWdhbikKbGlicmFyeShhcGUpCm1hdHJpeCA8LSB2ZWdkaXN0KGNvcmVfTEVNX3JlbEBvdHVfdGFibGUsIG1ldGhvZCA9ICJicmF5IikKc2F2ZShtYXRyaXgsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiZXRhX21hdHJpY2VzLlJEYXRhIikpCnBjb2Euc3ViIDwtIHBjb2EobWF0cml4KQpzYXZlKHBjb2Euc3ViLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAicGNvYS52YWx1ZXMuUkRhdGEiKSkKCiMgQ29udHJ1Y3Rpb24gb2YgdGhlIHRhYmxlIGZvciBncmFwaGljIApwY29hX2Nvb3JkIDwtIHBjb2Euc3ViJHZlY3RvcnNbLDE6M10KIyBfX19fXyBQQ09BIFBsb3QtLS0tLQpsaWJyYXJ5KHN0cmluZ3IpCnNhbXBfZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKGNvcmVfTEVNX3JlbCkpCnNhdmUoc2FtcF9kYXRhLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEuUkRhdGEiKSkKaHVsbCA8LSBjYmluZChwY29hX2Nvb3JkLCBzYW1wX2RhdGEpCmh1bGwkZ2VvbW9ycGhvIDwtIHN0cl9yZXBsYWNlX2FsbChodWxsJGdlb21vcnBobywgYygibWFjcm9hbGdhbCI9ICJNIiAsICJjb3JhbCI9IkMiKSkKCiMgV2hhdCBpcyB0aGUgcGVyY2VudGFnZSBvZiB0aGUgZXhwbGljYXRpdmUgdmFyaWFuY2U/IApwYXN0ZSgiQXhpcyAxIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSkpIApwYXN0ZSgiQXhpcyAyIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSkpIApwYXN0ZSgiQXhpcyAzIDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1szXSkpCnBhc3RlKCJBeGlzIDQgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzRdKSkKCnBjb2FfTEVNIDwtIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgY29sb3VyPSJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBodWxsLCBhZXMoeD1BeGlzLjEsIHk9QXhpcy4yLCBjb2xvciA9IGdlb21vcnBobyksIGFscGhhID0gMC43LCBzaXplID0gOCwgc2hhcGUgPSAxNikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrYmx1ZSIsImRhcmtyZWQiKSkrCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAgLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpKwogIGxhYnMoY29sb3VyID0gIlJlZWYiKQpwY29hX0xFTQpgYGAKCkZvciB0aGlzIHNwZWNpZXMsIHdlIGNhbiBvbmx5IHRlc3QgdGhlIGdlb21vcnBobyBhbmQgc2l0ZSBlZmZlY3QuIAoKYGBge3IgcGVybWFub3ZhIExFTSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CmFkb25pcyhtYXRyaXggfiBnZW9tb3JwaG8sIGRhdGEgPSBzYW1wX2RhdGEpCmFkb25pcyhtYXRyaXggfiBzaXRlLCBkYXRhID0gc2FtcF9kYXRhKQpgYGAKCiMjIyMgKkxldGhyaW51cyBlbmlnbWF0aWN1cyoKIyMjIyMgQWxwaGEgYW5kIGJldGEgZGl2ZXJzaXR5CgpgYGB7ciB3ZCBMRUUsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRn0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL1NoaWZ0L0xFRS8iKQpkaXIuY3JlYXRlKGRpcl9kYXRhX2NsZWFuaW5nLCByZWN1cnNpdmUgPSBUKQoKTEVFIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXQsIHRheDEgPT0gIkxldGhyaW51cyBtYWhzZW5hIikKTEVFIDwtIHBydW5lX3RheGEobmFtZXMod2hpY2goY29sU3VtcyhMRUVAb3R1X3RhYmxlKT4wKSksIExFRSkKc2F2ZShMRUUsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMRUUuUkRhdGEiKSkKTEVFcmZmIDwtIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoTEVFKSA+PSBtaW4oc2FtcGxlX3N1bXMoTEVFKSkgLCBMRUUpCkxFRXJmZiA8LSByYXJlZnlfZXZlbl9kZXB0aChMRUVyZmYgLG1pbihzYW1wbGVfc3VtcyhMRUVyZmYpKSkKc2F2ZShMRUVyZmYgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiTEVFcmZmLlJEYXRhIikpCmNvcmVfTEVFIDwtIHN1YnNldF9zYW1wbGVzKHNleV9ndXRfY29yZSwgdGF4MSA9PSAiTGV0aHJpbnVzIG1haHNlbmEiKQpjb3JlX0xFRSA8LSBwcnVuZV90YXhhKG5hbWVzKHdoaWNoKGNvbFN1bXMoY29yZV9MRUVAb3R1X3RhYmxlKT4wKSksIGNvcmVfTEVFKQpzYXZlKGNvcmVfTEVFLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9MRUUuUkRhdGEiKSkKYGBgCgpgYGB7ciBhbHBoYSBkaXYgTEVFLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KYm94MSA9IHBsb3RfcmljaG5lc3MoTEVFcmZmICwgbWVhc3VyZXMgPSBjKCJPYnNlcnZlZCIsIlNoYW5ub24iKSAsIGNvbG9yID0gImdlb21vcnBobyIpCiMgX19fXyBTaGFubm9uIGluZGV4IChFTlMpCmJveDEkZGF0YVtib3gxJGRhdGEkdmFyaWFibGUgPT0gIlNoYW5ub24iLF0kdmFsdWUgPSBleHAoYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSkKbGV2ZWxzKGJveDEkZGF0YSR2YXJpYWJsZSk9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwiU2hhbm5vbiAoRU5TKSIpCmxldmVscyhib3gxJGRhdGEkZ2VvbW9ycGhvKSA9IGMoIkMiICwgIk0iKQoKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ3Bsb3QyKQpwYWxldHRlID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikKCnNleV9MRUVfYWxwaGFfZGl2PSAgZ2dwbG90KGJveDEkZGF0YSwgYWVzKHggPSBmYWN0b3IoZ2VvbW9ycGhvKSAsIHkgPSB2YWx1ZSwgY29sb3IgPSBmYWN0b3IoZ2VvbW9ycGhvKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz0gcGFsZXR0ZSkgKyB0aGVtZV9idygpKwogIGdlb21fYm94cGxvdChhbHBoYT0wLjEsIG91dGxpZXIuY29sb3VyID0gTkEpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyNCwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDIiwgIk0iKSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFLCB0ZXh0c2l6ZT01LCBjb2xvcj0iYmxhY2siLCBmYW1pbHkgPSAic2VyaWYiKQoKc2V5X0xFRV9hbHBoYV9kaXYgCiMgX19fXyBUZXN0IE1XIC0tLS0KbGlicmFyeShwZ2lybWVzcykKIyBEb2VzIGV4aXN0IGRpZmZlcmVuY2VzIGluIGRpdmVyc2l0eSBiZXR3ZWVuIHR5cGVzIG9mIGhvc3Q/IAojIF9fX19fX19fX19fXyBPYnNlcnZlZCByaWNobmVzcyBNVyAKTVcub2JzID0gd2lsY294LnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl1+Ym94MSRkYXRhJGdlb21vcnBob1tib3gxJGRhdGEkdmFyaWFibGU9PSJPYnNlcnZlZCByaWNobmVzcyJdKQpNVy5vYnMgPSBjYmluZChNVy5vYnMkc3RhdGlzdGljLCBNVy5vYnMkcC52YWx1ZSkKIyBfX19fX19fX19fX18gU2hhbm5vbiBudW1iZXIgTVcgCk1XLnNoYW5ub24gPSB3aWxjb3gudGVzdChib3gxJGRhdGEkdmFsdWVbYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdfmJveDEkZGF0YSRnZW9tb3JwaG9bYm94MSRkYXRhJHZhcmlhYmxlPT0iU2hhbm5vbiAoRU5TKSJdKQpNVy5zaGFubm9uID1jYmluZChNVy5zaGFubm9uJHN0YXRpc3RpYywgTVcuc2hhbm5vbiRwLnZhbHVlKQojIF9fX19fX19fX19fXyBBbGwgY29tcHV0ZWQgCk1XLnRlc3QgPC0gcmJpbmQoTVcub2JzLCBNVy5zaGFubm9uKQpyb3duYW1lcyhNVy50ZXN0KSA9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwiU2hhbm5vbiAoRU5TKSIpCmNvbG5hbWVzKE1XLnRlc3QpID0gYygnVyBzdGF0JyAsICdwLXZhbHVlJykKTVcudGVzdApgYGAKCmBgYHtyIGJldGEtZGl2IExFRSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CmNvcmVfTEVFX3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhjb3JlX0xFRSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSApCnNhdmUoY29yZV9MRUVfcmVsICAsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJjb3JlX0xFRV9yZWwuUkRhdGEiKSkKIyBfX19fXyBQQ09BIGNvZGEgJiBwZXJtYW5vdmEgLS0tLS0tCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoYXBlKQptYXRyaXggPC0gdmVnZGlzdChjb3JlX0xFRV9yZWxAb3R1X3RhYmxlLCBtZXRob2QgPSAiYnJheSIpCnNhdmUobWF0cml4LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiYmV0YV9tYXRyaWNlcy5SRGF0YSIpKQpwY29hLnN1YiA8LSBwY29hKG1hdHJpeCkKc2F2ZShwY29hLnN1YiwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBjb2EudmFsdWVzLlJEYXRhIikpCgojIENvbnRydWN0aW9uIG9mIHRoZSB0YWJsZSBmb3IgZ3JhcGhpYyAKcGNvYV9jb29yZCA8LSBwY29hLnN1YiR2ZWN0b3JzWywxOjNdCiMgX19fX18gUENPQSBQbG90LS0tLS0KbGlicmFyeShzdHJpbmdyKQpzYW1wX2RhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShjb3JlX0xFRV9yZWwpKQpzYXZlKHNhbXBfZGF0YSxmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAic2FtcF9kYXRhLlJEYXRhIikpCmh1bGwgPC0gY2JpbmQocGNvYV9jb29yZCwgc2FtcF9kYXRhKQpodWxsJGdlb21vcnBobyA8LSBzdHJfcmVwbGFjZV9hbGwoaHVsbCRnZW9tb3JwaG8sIGMoIm1hY3JvYWxnYWwiPSAiTSIgLCAiY29yYWwiPSJDIikpCgojIFdoYXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIGV4cGxpY2F0aXZlIHZhcmlhbmNlPyAKcGFzdGUoIkF4aXMgMSA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0pKSAKcGFzdGUoIkF4aXMgMiA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0pKSAKcGFzdGUoIkF4aXMgMyA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbM10pKQpwYXN0ZSgiQXhpcyA0IDoiLHBlcmNlbnQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1s0XSkpCgpwY29hX0xFRSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9wb2ludChkYXRhID0gaHVsbCwgYWVzKHg9QXhpcy4xLCB5PUF4aXMuMiwgY29sb3IgPSBnZW9tb3JwaG8pLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDgsIHNoYXBlID0gMTYpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZGFya2JsdWUiLCJkYXJrcmVkIikpKwogIHhsYWIocGFzdGUoIlBDbzEgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMV0qMTAwLCAxKSwgIiUpIikpICsKICB5bGFiKHBhc3RlKCJQQ28yICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKjEwMCwgMSksICIlKSIpKSAgKwogIHRoZW1lX2J3KCkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLCBmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeC1heGlzIGxhYmVscwogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwICwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHktYXhpcyBsYWJlbHMKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1ham9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWlub3ItZ3JpZCBsYWJlbHMKICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUpKSsKICBsYWJzKGNvbG91ciA9ICJSZWVmIikKcGNvYV9MRUUKYGBgCgpGb3IgdGhpcyBzcGVjaWVzLCB3ZSBjYW4gb25seSB0ZXN0IHRoZSBnZW9tb3JwaG8gYW5kIHNpdGUgZWZmZWN0LiAKCmBgYHtyIHBlcm1hbm92YSBMRUUsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQphZG9uaXMobWF0cml4IH4gZ2VvbW9ycGhvLCBkYXRhID0gc2FtcF9kYXRhKQpgYGAKCgojIyMjIENvbmNsdXNpb24KPHN0eWxlPgpkaXYuYmx1ZSB7IGJhY2tncm91bmQtY29sb3I6I0ZCREZCNDsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAyMHB4O30KPC9zdHlsZT4KPGRpdiBjbGFzcyA9ICJibHVlIj4KPGZvbnQgc2l6ZT0iNCI+IEZpbmFsbHksIGl0IHNlZW1zIHRoYXQgdGhlIHNoaWZ0IGNvcmFsIC0gbWFjcm9hbGdhZSBkb2Vzbid0IGltcGFjdCB0aGUgZW50ZXJpYyBjb3JlIG1pY3JvYmlvbWUgb2YgdGhlIHJlZWYgZmlzaCB3aGlsZSB0aGUgY29yZSBlcGlwaHl0ZSBpcyBpbmZsdWVuY2VkIGJ5IHRoZSBlbnZpcm9ubWVudGFsIHBhcmFtZXRlcnMgYXMgZ2VvbW9ycGhvbG9neSwgc3Vic3RyYXQgYW5kIGxvY2F0aW9uLiBUaGlzIGhhcyBhbHJlYWR5IGJlZW4gZGVzY3JpYmVkIGluIG90aGVyIHN0dWRpZXMgcmVsYXRpbmcgb24gdGhlIG1pY3JvYmlvbWVzIG9mIGFsZ2FlICggW1NlcmVicnlha292YSBldCBhbC4sIDIwMThdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMzcxL2pvdXJuYWwucG9uZS4wMjA2NzM0KSkuIEEgdmVyeSB3ZWFrIHNpZ25hbCBpcyBkZXRlY3RlZCBmb3IgdGhlIGhlcmJpdm9yZXMgKlNjYXJ1cyBnaG9iYmFuKiBhbmQgd291bGQgaGF2ZSBtYXliZSBiZWVuIHNpZ25pZmljYW50IHdpdGggYSBoaWdoZXIgc2FtcGxpbmcgc2l6ZS4gTW9yZW92ZXIsIHRoZSBvYnNlcnZlZCBjaGFuZ2VzIGluIHRoZSBkaXZlcnNpdHkgYW5kIGJhY3RlcmlhbCBjb21wb3NpdGlvbnMgYXNzb2NpYXRlZCB0byBwcmltYXJ5IHByb2R1Y2VycyB3aXRoICpTYXJnYXNzdW0qIGFuZCB0dXJmIGFsZ2FlLCB3aGljaCBob2xkIGEgcGl2b3RhbCByb2xlIGFzIG1ham9yIG51dHJpdGlvbmFsIHJlc291cmNlcyBmb3IgU2lnYW5pZGFlIGFuZCBBY2FudGh1cmlkYWUgKCBbQ2hlYWwgZXQgYWwuLCAyMDEwXShodHRwczovL2RvaS5vcmcvMTAuMTAwNy9zMDAzMzgtMDEwLTA2NjEteSkpLCBsZXQgdXMgdGhpbmsgdG8gZnVydGhlciBjb25zZXF1ZW5jZXMgb24gdGhlIGVudGVyaWMgbWljcm9iaWFsIGNvbXBvc2l0aW9ucyBvZiB0aGVzZSBsYXR0ZXIuIE5vd2FkYXlzLCBJdCBpcyBxdWl0ZSBhZG1pdHRlZCB0aGF0IGRpZXQgaXMgb25lIG9mIHRoZSBzdHJvbmdlc3QgZGV0ZXJtaW5hbnQgb2YgZmlzaCBlbnRlcmljIG1pY3JvYmlvbWVzLiBNb3Jlb3Zlciwgc29tZSBzdHVkaWVzIGluIGFxdWFjdWx0dXJlIGhhdmUgZGVtb25zdHJhdGVkIHRoYXQgYSBtb2RpZmljYXRpb24gb2YgdGhlIGZvb2QgcXVhbGl0eSBtYXJrZWRseSBpbmZsdWVuY2VzIHRoZSB2YXJpYWJpbGl0eSBhbmQgZGl2ZXJzaXR5IG9mIGVudGVyaWMgbWljcm9iaW9tZXMgKCBbQnV0dCBldCBhbC4sIDIwMTldKGh0dHBzOi8vZG9pLm9yZy8xMC4zMzg5L2ZlbmRvLjIwMTkuMDAwMDkpKS4gQWxzbywgYXMgZGVtb25zdHJhdGVkIGluIHplYnJhZmlzaCBob3N0cywgdGhlIGFic2VuY2Ugb3IgZGVjcmVhc2luZyBhdmFpbGFiaWxpdHkgb2YgZm9vZCBtYXkgY2F1c2UgYSBzdHJlc3MgYW5kIGFjdCBhcyBhbiBpbXBvcnRhbnQgZmFjdG9yIG9mIHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgZW50ZXJpYyBtaWNyb2Jpb21lIGV2ZW4gZHlzYmlvc2lzICggW0NhbnRhcyBldCBhbC4sIDIwMTJdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDg5L3plYi4yMDExLjA3MTIpKS4gClRoZSByZXNpc3RlbmNlIG9mIHRoZSBlbnRlcmljIG1pY3JvYmlvbWUgYWdhaW5zdCBlbnZpcm9ubWVudGFsIHBlcnR1cmJhdGlvbiAobW9kaWZpY2F0aW9uL2Fic2VuY2Ugb2YgdGhlIGRpZXQgYmVjYXVzZSBvZiBoYWJpdGF0IGZyYWdtZW50YXRpb24gb3IgYW50aHJvcG9nZW5pemF0aW9uKSBoYXMgYmVlbiBvYnNlcnZlZCBpbiBub24gaHVtYW4gcHJpbWF0ZSBpbiBBZnJpY2Egd2hlcmUgdGhlIHNwZWNpZXMgaWRlbnRpdHkgcmVtYWluZWQgdGhlIHN0cm9uZ2VzdCBkZXRlcm1pbmFudCAoIFtNY0NvcmQgZXQgYWwuLCAyMDE0XShodHRwczovL2RvaS5vcmcvMTAuMTAwMi9hanAuMjIyMzgpKS4KSW4gb3VyIGNhc2UsIHdoYXQgYXJlIHRodXMgdGhlIHN0cm9uZ2VyIGRldGVybWluYW50cyB0aGF0IGluZmx1ZW5jZSB0aGUgZW50ZXJpYyBjb3JlIG1pY3JvYmlvbWU/IAo8L2Rpdj4KCgo8YSBpZD0iUGFydCBWSTogT3RoZXIgZHJpdmVycyBvZiBlbnRlcmljIG1pY3JvYmlhbCBjb21tdW5pdGllcyI+PC9hPiAKCiMjIFBhcnQgVkk6IE90aGVyIGRyaXZlcnMgb2YgZW50ZXJpYyBtaWNyb2JpYWwgY29tbXVuaXRpZXMKW2JhY2sgdG8gdG9wXSgjYmFjayB0byB0b3ApCgpUaGUgZGlldCBhbmQgdGhlIHRheG9ub215IGFyZSBrbm93biB0byBiZSBtYWpvciBkcml2ZXJzIG9mIHRoZSBtaWNyb2JpYWwgYXNzZW1ibGFnZSBpbiB0aGUgZ3V0IG9mICBmaXNoZXMuIFdlIGhhdmUgc2VlbiBwcmV2aW91c2x5IHNvbWUgZWZmZWN0IGF0IGRpZmZlcmVudCBzY2FsZS4gSGVyZSwgd2Ugd2lsbCBkZXNjcmliZSBhbmQgZGV0ZXJtaW5lIHdoaWNoIGFyZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgZGl2ZXJzaXR5IG9mIHRoZSBkaWZmZXJudCB0eXBlcyBvZiBkaWV0IGFuZCBmYW1pbGllcyBhbmQgdHJ5IHRvIGRldGVjdCBzb21lIGJpb21hcmtlcnMgd2hpY2ggY291bGQgcGxheSBhIGZ1bmN0aW9uYWwgcm9sZSBpbiB0aGUgbnV0cml0aW9uIG9mIHRoZSByZWVmIGZpc2guCgpgYGB7ciBmaXNoIGFsbCB3ZCAsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGIH0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL0NvcmUvQV9kaXYvIikKZGlyLmNyZWF0ZShkaXJfZGF0YV9jbGVhbmluZykKYGBgCgpMZXQncyBzZWUgYXQgZ3JhbnVsb3VzIHNjYWxlIG9mIGRpZXQgOkhlcmJpdm9yb3VzIHZzIGNhcm5pdm9yb3VzIHdpdGggdGhlIDMgb21uaXZvcm91cyBmaXNoZXMgY29uc2lkZXJlZCBhcyBoZXJiaXZvcm91cy4gCgojIyMjIEFscGhhIGFuZCBiZXRhIGRpdmVyc2l0eSAKYGBge3IgYWxwaGEgZGl2IGRpZXQsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciIgfQojIF9fX18gU2hhbm5vbiAoRU5TKSwgRmFpdGggUEQgYW5kIExDQkQgLS0tLQpsZXZlbHMoc2FtcGxlX2RhdGEoc2V5cmZmX2d1dCkkZGlldDMpWzNdID0gIkhlcmJpdm9yb3VzIgpib3gxID0gcGxvdF9yaWNobmVzcyhzZXlyZmZfZ3V0ICwgbWVhc3VyZXMgPSBjKCJPYnNlcnZlZCIsIlNoYW5ub24iKSAsIGNvbG9yID0gImRpZXQzIikKIyBfX19fIFNoYW5ub24gaW5kZXggKEVOUykKYm94MSRkYXRhW2JveDEkZGF0YSR2YXJpYWJsZSA9PSAiU2hhbm5vbiIsXSR2YWx1ZSA9IGV4cChib3gxJGRhdGFbYm94MSRkYXRhJHZhcmlhYmxlID09ICJTaGFubm9uIixdJHZhbHVlKQpsZXZlbHMoYm94MSRkYXRhJHZhcmlhYmxlKSA9IGMoIk9ic2VydmVkIHJpY2huZXNzIiwgIlNoYW5ub24gKEVOUykiKQoKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ3Bsb3QyKQpwYWxldHRlID0gYygiZGFya3JlZCIgLCAiZGFya2dyZWVuIikKCnNleV9hbHBoYV9kaXZfZGlldCA9ICBnZ3Bsb3QoYm94MSRkYXRhLCBhZXMoeCA9IGZhY3RvcihkaWV0MykgLCB5ID0gdmFsdWUsIGNvbG9yID0gZmFjdG9yKGRpZXQzKSkpICsgCiAgZ2VvbV9qaXR0ZXIocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjApLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsgdGhlbWVfYncoKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuMSwgb3V0bGllci5jb2xvdXIgPSBOQSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkrCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIixzaXplID0gMTQpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAxNSwgYW5nbGUgPSAwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLHNpemUgPSAyMCwgYW5nbGUgPSAwKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFtaWx5ID0gInNlcmlmIikpICsgCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoIkNhcm5pdm9yb3VzIiwgIkhlcmJpdm9yb3VzIikpLCBtYXBfc2lnbmlmX2xldmVsID0gVFJVRSwgdGV4dHNpemU9NSwgY29sb3I9ImJsYWNrIiwgZmFtaWx5ID0gInNlcmlmIikrCiAgZmFjZXRfd3JhcCggfiB2YXJpYWJsZSwgbnJvdz0xLCBuY29sPTUsIHNjYWxlcyA9ICJmcmVlIikKc2V5X2FscGhhX2Rpdl9kaWV0CgoKIyBfX19fIER1bm4gdGVzdCAtLS0tCmxpYnJhcnkocGdpcm1lc3MpCmxpYnJhcnkoZHVubi50ZXN0KQojIERvZXMgZXhpc3QgZGlmZmVyZW5jZXMgaW4gZGl2ZXJzaXR5IGJldHdlZW4gZGlldHM/IAojIF9fX19fX19fX19fXyBPYnNlcnZlZCBkdW5uIApkdW5uLnRlc3QoYm94MSRkYXRhJHZhbHVlW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl0sYm94MSRkYXRhJGRpZXQxW2JveDEkZGF0YSR2YXJpYWJsZT09Ik9ic2VydmVkIHJpY2huZXNzIl0sIG1ldGhvZCA9ICJib25mZXJyb25pIikKIyBfX19fX19fX19fX18gU2hhbm5vbiBudW1iZXIgZHVubiAKZHVubi50ZXN0KGJveDEkZGF0YSR2YWx1ZVtib3gxJGRhdGEkdmFyaWFibGU9PSJTaGFubm9uIChFTlMpIl0sYm94MSRkYXRhJGRpZXQxW2JveDEkZGF0YSR2YXJpYWJsZT09IlNoYW5ub24gKEVOUykiXSwgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpgYGAKCmBgYHtyIGJldGEgZGl2IGRpZXQgLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KZGlyX2RhdGFfY2xlYW5pbmcgPC0gcGFzdGUwKHBhdGgsICIvYW5hbHlzZXMvMDRfZGF0YV9jbGVhbmluZy9GaXNoL0NvcmUvQl9kaXYvIikKZGlyLmNyZWF0ZShkaXJfZGF0YV9jbGVhbmluZykKCmNvcmVfZ3V0X3JlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhzZXlfZ3V0X2NvcmUsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkgKQpzYXZlKGNvcmVfZ3V0X3JlbCAgLCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiY29yZV9ndXRfcmVsLlJEYXRhIikpCiMgX19fX18gUENPQSBjb2RhICYgcGVybWFub3ZhIC0tLS0tLQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGFwZSkKbWF0cml4IDwtIHZlZ2Rpc3QoY29yZV9ndXRfcmVsQG90dV90YWJsZSwgbWV0aG9kID0gImJyYXkiKQpzYXZlKG1hdHJpeCwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImJldGFfbWF0cmljZXMuUkRhdGEiKSkKcGNvYS5zdWIgPC0gcGNvYShtYXRyaXgpCnNhdmUocGNvYS5zdWIsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJwY29hLnZhbHVlcy5SRGF0YSIpKQoKIyBDb250cnVjdGlvbiBvZiB0aGUgdGFibGUgZm9yIGdyYXBoaWMgCnBjb2FfY29vcmQgPC0gcGNvYS5zdWIkdmVjdG9yc1ssMTozXQojIF9fX19fIFBDT0EgUGxvdC0tLS0tCmxpYnJhcnkoc3RyaW5ncikKc2FtcF9kYXRhIDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEoY29yZV9ndXRfcmVsKSkKbGV2ZWxzKHNhbXBfZGF0YSRkaWV0MykgPC0gYygiQ2Fybml2b3JvdXMiLCAiSGVyYml2b3JvdXMiLCJIZXJiaXZvcm91cyIpCnNhdmUoc2FtcF9kYXRhLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJzYW1wX2RhdGEuUkRhdGEiKSkKI3dyaXRlLnRhYmxlKHNhbXBfZGF0YSwgZmlsZSA9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNhbXBfZGF0YS50eHQiKSwgcXVvdGUgPSBGLCBzZXAgPSAiXHQiKQpodWxsIDwtIGNiaW5kKHBjb2FfY29vcmQsIHNhbXBfZGF0YSkKaHVsbCRnZW9tb3JwaG8gPC0gc3RyX3JlcGxhY2VfYWxsKGh1bGwkZ2VvbW9ycGhvLCBjKCJtYWNyb2FsZ2FsIj0gIk0iICwgImNvcmFsIj0iQyIpKQoKIyBXaGF0IGlzIHRoZSBwZXJjZW50YWdlIG9mIHRoZSBleHBsaWNhdGl2ZSB2YXJpYW5jZT8gCnBhc3RlKCJBeGlzIDEgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKSkgCnBhc3RlKCJBeGlzIDIgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzJdKSkgCnBhc3RlKCJBeGlzIDMgOiIscGVyY2VudChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzNdKSkKcGFzdGUoIkF4aXMgNCA6IixwZXJjZW50KHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbNF0pKQoKcGNvYV9kaWV0MSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGNvbG91cj0ibGlnaHRncmV5IiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9wb2ludChkYXRhID0gaHVsbCwgYWVzKHg9QXhpcy4xLCB5PUF4aXMuMiwgY29sb3IgPSBkaWV0MSksIGFscGhhID0gMC43LCBzaXplID0gOCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAgYygiRGFya3JlZCIsICJEYXJrZ3JlZW4iLCJEYXJra2hha2kiLCJEYXJrb3JhbmdlIiwiRGFya29yY2hpZCIpKSsKICB4bGFiKHBhc3RlKCJQQ28xICgiLCByb3VuZChwY29hLnN1YiR2YWx1ZXMkUmVsYXRpdmVfZWlnWzFdKjEwMCwgMSksICIlKSIpKSArCiAgeWxhYihwYXN0ZSgiUENvMiAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1syXSoxMDAsIDEpLCAiJSkiKSkgICsKICB0aGVtZV9idygpICsKICBjb29yZF9lcXVhbCgpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCwgZmFtaWx5ID0gInNlcmlmIiksICMgcmVtb3ZlIHgtYXhpcyBsYWJlbHMKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCAsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB5LWF4aXMgbGFiZWxzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtYWpvci1ncmlkIGxhYmVscwogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAjcmVtb3ZlIG1pbm9yLWdyaWQgbGFiZWxzCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSkrCiAgbGFicyhjb2xvdXIgPSAiRGlldCIpCnBjb2FfZGlldDEKCnBjb2FfZGlldDMgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBjb2xvdXI9ImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGh1bGwsIGFlcyh4PUF4aXMuMSwgeT1BeGlzLjIsIGNvbG9yID0gZGlldDMpLCBhbHBoYSA9IDAuNywgc2l6ZSA9IDgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiRGFya3JlZCIsICJEYXJrZ3JlZW4iKSkrCiAgeGxhYihwYXN0ZSgiUENvMSAoIiwgcm91bmQocGNvYS5zdWIkdmFsdWVzJFJlbGF0aXZlX2VpZ1sxXSoxMDAsIDEpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUoIlBDbzIgKCIsIHJvdW5kKHBjb2Euc3ViJHZhbHVlcyRSZWxhdGl2ZV9laWdbMl0qMTAwLCAxKSwgIiUpIikpICArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhbWlseSA9ICJzZXJpZiIpLCAjIHJlbW92ZSB4LWF4aXMgbGFiZWxzCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MjAgLCBmYW1pbHkgPSAic2VyaWYiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJzZXJpZiIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFtaWx5ID0gInNlcmlmIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNixmYW1pbHkgPSAic2VyaWYiKSwgIyByZW1vdmUgeS1heGlzIGxhYmVscwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICNyZW1vdmUgbWFqb3ItZ3JpZCBsYWJlbHMKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgI3JlbW92ZSBtaW5vci1ncmlkIGxhYmVscwogICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSkpKwogIGxhYnMoY29sb3VyID0gIkRpZXQiKQpwY29hX2RpZXQzCmBgYAoKVGhlIGhlcmJpdm9yZXMgYW5kIGNhcm5pdm9yZXMgc2VlbSB0byBjb21wb3NlIHR3byBkaWZmZXJlbnQgY2x1c3RlcnMgd2VsbCBkZWZpbmVkLiBMZXQncyB0ZXN0IHRoZSBpbmZsdWVuY2Ugb2YgdGhlIGRpZXQ6IAoKYGBge3IgcGVybWFub3ZhIGRpZXQgLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KIyBCZXR3ZWVuIGRpZXRzCmFkb25pcyhtYXRyaXggfiBkaWV0MSwgZGF0YSA9IHNhbXBfZGF0YSkKYGBgClRoZSB0YXhvbm9teSBjYW4gYWxzbyBwbGF5IGEgcm9sZSBpbiB0aGUgZGV0ZXJtaW5hdGlvbiBvZiB0aGUgbWljcm9iaWFsIGNvbXBvc2l0aW9uLCBzbyB3aGF0IGlzIHRoZSBlZmZlY3Qgb2YgdGhlIHRheG9ub215PyAKYGBge3IgcGVybWFub3ZhIGZhbWlseSwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGLCBmaWcuYWxpZ249ImNlbnRlciJ9CiMgQmV0d2VlbiBmYW1pbGllcwphZG9uaXMobWF0cml4IH4gdGF4MSwgZGF0YSA9IHNhbXBfZGF0YSkKYGBgCgpUbyB0ZXN0IHRoZSBlZmZlY3Qgb2YgdGhlIGRpZXQgaW5zaWRlIGEgdGF4b25vbWljIGxldmVsLCB3ZSBmcmVlemUgdGhlIGRpZXQgYW5kIHNlZSB3aGF0IGlzIHRoZSBlZmZlY3Qgb2YgdGhlIGZhbWlseSwgYW5kIGluc2lkZSB0aGUgZmFtaWx5LCB0aGUgZWZmZWN0IG9mIHRoZSBnZW51cywgYW5kIGluc2lkZSBhIGdlbnVzLCB0aGUgZWZmZWN0IG9mIGEgc3BlY2llcy4gQWN0dWFsbHksIHdlIHRlc3RlZCB0aGUgZWZmZWN0IGJldHdlZW4gc3BlY2llcyBhbmQgZ2VudXMsIHNoYXJpbmcgdGhlIHNhbWUgZmFtaWx5LCB3aXRoIHRoZSBlZmZlY3Qgb2YgdGhlIGRpZXQgYmxvY2tlZCAoaW4gY2FzZSBvZiBkaWZmZXJlbnQgZGlldCBpbnNpZGUgZmFtaWx5IHdoaWNoIGNhbiBvY2N1ciBiZXR3ZWVuIHBpc2Npdm9yb3VzIGFuZCBpbnZlcnRpdm9yZXMgaW4gdGhlIEx1dGphbmlkYWUgZmFtaWx5KS4KCmBgYHtyIHBlcm1hbm92YSBjYXNjYWRlLCBlY2hvID0gVCwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEYsIGZpZy5hbGlnbj0iY2VudGVyIn0KYWRvbmlzKG1hdHJpeCB+ICBkaWV0My9mYW1pbHkgLyBnZW51cyAvIHRheDEsIHN0cmF0YSA9IHNhbXBfZGF0YSRkaWV0MywgZGF0YSA9IHNhbXBfZGF0YSkgCmBgYAoKIyMjIyBMRWZTZSBiZXR3ZWVuIGRpZXQKVG8gZGV0ZWN0IG5vdyBiaW9tYXJrZXJzIGluIGhlcmJpdm9yZXMgYW5kIGNhcm5pdm9yZXMsIHdlIGFwcGx5IGFuIGRpc2NyaW1pbmFudCBhbmFseXNpcyB3aXRoIExFZnNFIGFuYWx5c2lzLiAKCmBgYHtyIExEQSB3ZDIsIGVjaG89IEYsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0Zpc2gvQ29yZS9MREEvIikKZGlyLmNyZWF0ZShkaXJfZGF0YV9jbGVhbmluZywgcmVjdXJzaXZlID0gVCkKYGBgCgpgYGB7ciBMRWZTZSBwcmVwYXJhdGlvbiBkYXRhMiwgZWNobz0gRiwgZXZhbD0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2U9IEZ9CnNleV9ndXQuZ2VudXMgPC0gdGF4X2dsb20oc2V5X2d1dF9jb3JlLCAiR2VudXMiLCBOQXJtID0gVFJVRSkgI21lcmdlcyBzcGVjaWVzIHRoYXQgaGF2ZSB0aGUgc2FtZSBHZW51cyArIGZpbHRyZSBHZW5yZXMgTkEKc2V5X2d1dC5nZW51c0BzYW1fZGF0YSRkaWV0M1tzZXlfZ3V0LmdlbnVzQHNhbV9kYXRhJGRpZXQzID09ICJPbW5pdm9yb3VzIl0gPC0gIkhlcmJpdm9yb3VzIgoKIyBfX19fIExFZlNFIGZpbGUgY3JlYXRpb24gIC0tLS0KdGF4byA9IGRhdGEuZnJhbWUodGF4X3RhYmxlKHNleV9ndXQuZ2VudXMpKQp0YXhfbmFtZSA8LSBwYXN0ZSh0YXhvJERvbWFpbiwgdGF4byRQaHlsdW0sIHRheG8kQ2xhc3MsIHRheG8kT3JkZXIsIHRheG8kRmFtaWx5LCB0YXhvJEdlbnVzLCAgc2VwPSJ8IikKdGF4X25hbWUyIDwtIGMoImRpZXQzIix0YXhfbmFtZSkKc2F2ZSh0YXhvLCB0YXhfbmFtZTIsIGZpbGU9cGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nICwgInNleV9ndXQuZ2VudXNfdGF4by5SRGF0YSIpKQoKc2FtcF9kYXRhIDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEoc2V5X2d1dC5nZW51cykpCmRpZXRfbGVmc2UgPC0gZGF0YS5mcmFtZShzYW1wX2RhdGFbLDEyXSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpvdHUgPSBkYXRhLmZyYW1lKG90dV90YWJsZShzZXlfZ3V0LmdlbnVzKSkKIyBPbiBkaWV0CmxlZnNlIDwtIGNiaW5kKGRpZXRfbGVmc2UsIG90dSkKbGVmc2UyIDwtIGNiaW5kKHRheF9uYW1lMix0KGxlZnNlKSkKd3JpdGUudGFibGUobGVmc2UyLCBmaWxlPXBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgImxlZnNlX2RpZXRfc2V5LnR4dCIpLCAKICAgICAgICAgICAgc2VwPSJcdCIsIHJvdy5uYW1lcz1GQUxTRSwgY29sLm5hbWVzPUZBTFNFLCBxdW90ZT1GQUxTRSkKIyBSdW4geW91ciBmaWxlIGluIExFZlNFIHNvZnR3YXJlIG9uIEdhbGF4eSwgZG93bmxvYWQgdGhlIHJlc3VsdHMsIG1vdmUgaXQgb24geW91ciBhY3RpdmUgZm9sZGVyICJkaXJfZGF0YV9jbGVhbmluZyIgYW5kIHJlbmFtZSB0aGUgZmlsZSAiTERBX3Jlc3VsdHMiLgoKYGBgCgpQcm9jZWVkIHRoZSAibGVmc2VfdHlwZV9zZXkudHh0IiBpbiBhIExFZnNlIEdhbGF4eSBhbmQgcmV0cmlldmUgZGF0YSAiTERBIEVmZmVjdCBTaXplIiB3aXRoIHRoZSBhc3NvY2lhdGVkICJQbG90IExFZlNlIFJlc3VsdHMiIGluIHRoZSBMREEgZm9sZGVyLllvdSBoYXZlIHRvIHJlbmFtZSB0aGUgZm9ybWVyIGZpbGUgIkxEQV9yZXN1bHRzIiBhbmQgcnVuIHRoZSBmb2xsb3dpbmcgY29kZS4gCgpgYGB7ciB3cml0ZSBMREEgcmVzdWx0czIsZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfSAKbGlicmFyeShwbHlyKQpMREFfRWZmZWN0X1NpemUgPC0gcmVhZC5kZWxpbShwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMREFfcmVzdWx0cyIpLCBoZWFkZXI9RkFMU0UpCkxEQV9jYXJuIDwtIHN1YnNldChMREFfRWZmZWN0X1NpemUgLCBMREFfRWZmZWN0X1NpemUkVjMgPT0gIkNhcm5pdm9yb3VzIikKTERBX2hlcmIgPC0gc3Vic2V0KExEQV9FZmZlY3RfU2l6ZSAsIExEQV9FZmZlY3RfU2l6ZSRWMyA9PSAiSGVyYml2b3JvdXMiKQpMREFfZGlldCA8LSByYmluZChMREFfY2FybixMREFfaGVyYikKTERBX3BoeWx1bSA8LSBMREFfZGlldCRWMQpuYW1lcyhMREFfcGh5bHVtKSA8LSBhcy5mYWN0b3IoIi5QaHlsdW0uQ2xhc3MuT3JkZXIuRmFtaWx5LkdlbnVzIikgI3Bhc3RlIHRoZSBuYW1lcyhMREFfcGh5bHVtKSBpbiBleGNlbAojd3JpdGUudGFibGUoTERBX3BoeWx1bSwgZmlsZT1wYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMREFfcGh5bHVtLnR4dCIpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzPUYsIGNvbC5uYW1lcz1GLCBxdW90ZT1GQUxTRSkKbGlicmFyeShyZWFkcikKTERBX3BoeWx1bSA8LSByZWFkX2RlbGltKHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgIkxEQV9waHlsdW0udHh0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIi4iLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIGNvbF90eXBlcyA9IGNvbHMoWDEgPSBjb2xfc2tpcCgpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB0cmltX3dzID0gVFJVRSkKTERBX3BoeWx1bV9kaWV0IDwtIGNiaW5kKExEQV9waHlsdW0gLCBMREFfZGlldFssMjo1XSkKY29sbmFtZXMoTERBX3BoeWx1bV9kaWV0KSA8LSBjKG5hbWVzKExEQV9waHlsdW0pWzE6NV0gLCAiTERBX3JlcyIgLCAiRGlldCIgLCAiTERBX3JlczIiICwgInNpZyIpCndyaXRlLnRhYmxlKExEQV9waHlsdW1fZGlldCwgZmlsZT1wYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJMREFfcGh5bHVtX2RpZXQudHh0IiksIHNlcD0iXHQiLCByb3cubmFtZXM9RiwgY29sLm5hbWVzPVQsIHF1b3RlPUZBTFNFKQoKIyBTZWxlY3QgeW91ciBzaWduaWZpY2F0aXYgdmFsdWUgYW5kIHRheGEKTEVGU0Vfc2lnIDwtIHN1YnNldChMREFfcGh5bHVtX2RpZXQsIExEQV9waHlsdW1fZGlldCRMREFfcmVzMiA+PSAzKQpMRUZTRV9zaWdfZ2VudXMgPC0gc3Vic2V0KExFRlNFX3NpZywgTEVGU0Vfc2lnJEdlbnVzICVpbiUgYXMuY2hhcmFjdGVyKG5hLmV4Y2x1ZGUoTEVGU0Vfc2lnJEdlbnVzKSkpCkxFRlNFX3NpZ19nZW51c192ZWMgPC0gcGFzdGUoTEVGU0Vfc2lnX2dlbnVzJFBoeWx1bSwgTEVGU0Vfc2lnX2dlbnVzJENsYXNzLCBMRUZTRV9zaWdfZ2VudXMkT3JkZXIsIExFRlNFX3NpZ19nZW51cyRGYW1pbHksIExFRlNFX3NpZ19nZW51cyRHZW51cywgc2VwID0gInwiKQoKYmlvbWFya2VycyA8LSBwYXN0ZShMRUZTRV9zaWdfZ2VudXMkT3JkZXIsIExFRlNFX3NpZ19nZW51cyRHZW51cywgc2VwID0gInwiKQpzYXZlKGJpb21hcmtlcnMsIGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiaW9tYXJrZXJzLlJEYXRhIikpCgpzZXlfc2FtcCA8LSBzZXlfZ3V0LmdlbnVzQHNhbV9kYXRhCndyaXRlLnRhYmxlKHNleV9zYW1wLCBmaWxlPXBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInNleV9zYW1wLnR4dCIpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzPUYsIGNvbC5uYW1lcz1ULCBxdW90ZT1GQUxTRSkKbGV2ZWxzKHNhbXBsZV9kYXRhKHNleV9ndXQuZ2VudXMpJGRpZXQzKSA8LSBjKCJDYXJuaXZvcm91cyIsICJIZXJiaXZvcm91cyIsIkhlcmJpdm9yb3VzIikKCnBoeXNlcV9waHlsdW0gPC0gc2V5X2d1dC5nZW51cyAlPiUgICAgCiAgdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoZnVuY3Rpb24oeCkge3gvc3VtKHgpfSApICU+JSAjIFRyYW5zZm9ybSB0byByZWwuIGFidW5kYW5jZQogIHBzbWVsdCgpICU+JSAgCiAgZmlsdGVyKEFidW5kYW5jZSA+IDApICU+JSAjIE1lbHQgdG8gbG9uZyBmb3JtYXQKICBhcnJhbmdlKEdlbnVzKQoKcGh5c2VxX3BoeWx1bSRBYnVuZGFuY2UgPC0gcGh5c2VxX3BoeWx1bSRBYnVuZGFuY2UvbnJvdyhzYW1wbGVfZGF0YShzZXlfZ3V0LmdlbnVzKSkKCnBoeXNlcV9waHlsdW0kdGF4IDwtIHBhc3RlKHBoeXNlcV9waHlsdW0kUGh5bHVtLCBwaHlzZXFfcGh5bHVtJENsYXNzLCBwaHlzZXFfcGh5bHVtJE9yZGVyLCBwaHlzZXFfcGh5bHVtJEZhbWlseSwgcGh5c2VxX3BoeWx1bSRHZW51cywgc2VwID0gInwiKQpzYXZlKHBoeXNlcV9waHlsdW0sIGZpbGU9IHBhc3RlMChkaXJfZGF0YV9jbGVhbmluZywgInBoeXNlcV9waHlsdW0uUkRhdGEiKSkKI3dyaXRlLnRhYmxlKHBoeXNlcV9waHlsdW0gLGZpbGUgPSBwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJwaHlzZXFfcGh5bHVtLnR4dCIpLCBzZXA9Ilx0IixxdW90ZSA9IEYpCgpEaWV0X1BvbF9zZXkgPC0gcGh5c2VxX3BoeWx1bQpEaWV0X1BvbF9zZXkkdGF4IDwtICBwYXN0ZShEaWV0X1BvbF9zZXkkT3JkZXIsIERpZXRfUG9sX3NleSRHZW51cywgc2VwID0gInwiKQpsZW5ndGgocGh5c2VxX3BoeWx1bSR0YXgpCgpkZl9zZXkgPC0gRGlldF9Qb2xfc2V5WyxjKCJkaWV0MyIsInRheDMiLCJ0YXgiLCJBYnVuZGFuY2UiKV0KY29sbmFtZXMoZGZfc2V5KSA8LSBjKCJmYW1pbHkiLCJpdGVtIiwic2NvcmUiLCJ2YWx1ZSIpCnNhdmUoZGZfc2V5LCBmaWxlID0gcGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiZGZfc2V5LlJEYXRhIikpCmBgYAoKTGV0J3Mgb3JnYW5pemUgb3VyIGRhdGEgdG8gcGxvdCBjb3JyZXNwb25kaW5nIGNvbG91cnMgZGVwZW5kaW5nIG9uIHRoZSAgY29tcGFydG1lbnQuIAoKYGBge3IgcG9sYXJoaXN0b2dyYW0gb24gZGlldCwgZWNobyA9IFQsIGV2YWw9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPSBGfQpkaXJfZGF0YV9jbGVhbmluZyA8LSBwYXN0ZTAocGF0aCwgIi9hbmFseXNlcy8wNF9kYXRhX2NsZWFuaW5nL0Zpc2gvQ29yZS9MREEvIikKbG9hZChwYXN0ZTAoZGlyX2RhdGFfY2xlYW5pbmcsICJiaW9tYXJrZXJzLlJEYXRhIikpCmxvYWQocGFzdGUwKGRpcl9kYXRhX2NsZWFuaW5nLCAiZGZfc2V5LlJEYXRhIikpCmxpYnJhcnkocGx5cikKcHJpbnRfYmlvbWFya2VycyA8LSBsZXZlbHMoZmFjdG9yKGRmX3NleVtkZl9zZXkkc2NvcmUgJWluJSBiaW9tYXJrZXJzLF0kc2NvcmUpKSAjIEFsbCBiaW9tYXJrZXJzIHByZXNlbnQgaW4gdGhlIHNleS5kaWV0X2dlbnVzIFJEYXRhIGZpbGUKb3RoZXJzIDwtIGxldmVscyhmYWN0b3IoZGZfc2V5WyFkZl9zZXkkc2NvcmUgJWluJSBiaW9tYXJrZXJzLF0kc2NvcmUpKSAjIEFsbCB0YXhhIHdoaWNoIGFyZSBub3QgYmlvbWFya2VycwpkZl9zZXlbIWRmX3NleSRzY29yZSAlaW4lIGJpb21hcmtlcnMsXSRzY29yZSA8LSAiWi1PdGhlciIgIyBDYWxsIHRoZW0gb3RoZXIgKFogdG8gZmlndXJlIGF0IHRoZSBlbmQgb2YgdGhlIGxpc3QpCgojIFNvbWUgYmlvbWFya2VycyBhcmUgaW4gY29tbW9uIHNvIE91dHB1dCB0aGUgZnJlcXVlbmNlcy4KZnJlcV9oZXJiIDwtIHRhYmxlKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJIZXJiaXZvcm91cyIsXSRzY29yZSkvbGVuZ3RoKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJIZXJiaXZvcm91cyIsXSRzY29yZSkqMTAwIApmcmVxX2hlcmIgPC0gZnJlcV9oZXJiWyFuYW1lcyhmcmVxX2hlcmIpID09ICJaLU90aGVyIl0KZnJlcV9jYXJuIDwtIHRhYmxlKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJDYXJuaXZvcm91cyIsXSRzY29yZSkvbGVuZ3RoKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJDYXJuaXZvcm91cyIsXSRzY29yZSkqMTAwIApmcmVxX2Nhcm4gPC0gZnJlcV9jYXJuWyFuYW1lcyhmcmVxX2Nhcm4pID09ICJaLU90aGVyIl0KCiMgS2VlcCB0aGUgY29tbW9uIGJpb21hcmtlcnMgb2YgdGhlIGhlcmJpdm9yb3VzIGFuZCBjYXJuaXZvcm91cyBhbmQgdGhlIHJlc3BlY3RpdmUgZnJlcXVlbmNpZXMgaW4gZWFjaCBjb21wYXJ0bWVudApiaW9tX2NvbW1vbiA8LSBuYW1lcyhmcmVxX2hlcmJbd2hpY2gobmFtZXMoZnJlcV9oZXJiKSAlaW4lIG5hbWVzKGZyZXFfY2FybikpXSkKZnJlcV9oZXJiX2NvbW1vbiA8LSBhcy5kYXRhLmZyYW1lKGZyZXFfaGVyYltuYW1lcyhmcmVxX2hlcmIpICVpbiUgYmlvbV9jb21tb25dKQpmcmVxX2Nhcm5fY29tbW9uIDwtIGFzLmRhdGEuZnJhbWUoZnJlcV9jYXJuW25hbWVzKGZyZXFfY2FybikgJWluJSBiaW9tX2NvbW1vbl0pCmZyZXFfY29tbW9uIDwtIGNiaW5kKGZyZXFfaGVyYl9jb21tb24sIGZyZXFfY2Fybl9jb21tb24kRnJlcSkKY29sbmFtZXMoZnJlcV9jb21tb24pIDwtIGMoIkJpb21hcmtlcnMiLCAiRnJlcV9oZXJiIiAsIkZyZXFfY2FybiIpCiMgQ2xhc3MgdGhlIGJpb21hcmtlcnMgaW4gdGhlIGNvbXBhcnRtZW50IHdoZXJlIHRoZSB2YWx1ZSBpcyB0aGUgaGlnaGVyCmJpb21faGVyYl90b19rZWVwIDwtIGZyZXFfY29tbW9uJEJpb21hcmtlcnNbd2hpY2goZnJlcV9jb21tb24kRnJlcV9oZXJiID4gZnJlcV9jb21tb24kRnJlcV9jYXJuLCBUKV0KYmlvbV9jYXJuX3RvX2tlZXAgPC0gZnJlcV9jb21tb24kQmlvbWFya2Vyc1t3aGljaChmcmVxX2NvbW1vbiRGcmVxX2Nhcm4gPiBmcmVxX2NvbW1vbiRGcmVxX2hlcmIsIFQpXQojIFNlZSB3aGljaCBhcmUgdGhlIGJpb21hcmtlcnMgZm9yIHRoZSBoZXJiaXZvcm91cyBhbmQgd2hpY2ggYXJlIHRoZSBiaW9tYXJrZXJzIGZvciB0aGUgY2Fybml2b3JvdXMKYmlvbV9oZXJiIDwtIGxldmVscyhmYWN0b3IoZGZfc2V5W2RmX3NleSRmYW1pbHkgPT0gIkhlcmJpdm9yb3VzIixdJHNjb3JlKSkKYmlvbV9oZXJiIDwtIGJpb21faGVyYlshYmlvbV9oZXJiID09ICJaLU90aGVyIl0KYmlvbV9oZXJiIDwtIGJpb21faGVyYlshYmlvbV9oZXJiICVpbiUgYmlvbV9jYXJuX3RvX2tlZXBdCmJpb21fY2FybiA8LSBsZXZlbHMoZmFjdG9yKGRmX3NleVtkZl9zZXkkZmFtaWx5ID09ICJDYXJuaXZvcm91cyIsXSRzY29yZSkpCmJpb21fY2FybiA8LSBiaW9tX2Nhcm5bIWJpb21fY2FybiA9PSAiWi1PdGhlciJdCmJpb21fY2FybiA8LSBiaW9tX2Nhcm5bIWJpb21fY2FybiAlaW4lIGJpb21faGVyYl90b19rZWVwXQoKIyBDb2xvciBjaG9pY2UKaGVyYl9jb2xvcnMgPC0gYygieWVsbG93IiAsICJkYXJra2hha2kiLCAiZGFya29saXZlZ3JlZW4iLAogICAgICAgICAgICAgICAgICAiZGFya29saXZlZ3JlZW4yIiwiZ29sZDQiLCJjaGFydHJldXNlIiwKICAgICAgICAgICAgICAgICAgImFxdWFtYXJpbmUiLCJkYXJrZ3JlZW4iLCAiZGFya2N5YW4iLAogICAgICAgICAgICAgICAgICAiZGFya3NlYWdyZWVuIiwgImdvbGQzIiwgImRhcmtzbGF0ZWdyYXkiKQogICAgICAgICAgICAgICAgIApwaWUocmVwKDEsIDEyKSwgY29sPSBoZXJiX2NvbG9ycykKCmNhcm5fY29sb3JzIDwtIGMoImRhcmtyZWQiLCJkYXJrc2FsbW9uIiwiZGFya29yY2hpZDQiLAogICAgICAgICAgICAgICAgImJsdWV2aW9sZXQiLCJkYXJrYmx1ZSIsCiAgICAgICAgICAgICAgICAiYmx1ZTMiLCAiYnJvd24xIiwiZGVlcHBpbmsiKQoKcGllKHJlcCgxLCA4KSwgY29sPSBjYXJuX2NvbG9ycykKCnBvbGFyX2NvbCA8LSBjKGNhcm5fY29sb3JzICwgaGVyYl9jb2xvcnMgLCAnWl9PdGhlcic9ImJsYWNrIikKIyBBZGQgYSBwcmVmaXggSCAoZm9yIGhlcmJpdm9yb3VzKSBvciBDIChmb3IgY2Fybml2b3JvdXMpIGluIHRoZWlyIHJlc3BlY3RpdiBiaW9tYXJrZXJzLiBJbiB0aGlzIHdheSwgdGhleSB3aWxsIGJlIGxpc3RlZCBmb2xsb3dpbmcgCiMgdGhlaXIgcmVzcGVjdGl2IGNvbXBhcnRtZW50IGFuZCBubyB0aGVpciBuYW1lcyAoZWFzaWVyIGZvciB0aGUgYWRkIG9mIHRoZSBjb2xvciBpbiB0aGUgZ2dwbG90KQpkZl9zZXlbZGZfc2V5JHNjb3JlICVpbiUgYmlvbV9oZXJiLF0kc2NvcmUgPC0gcGFzdGUoIkgiLGRmX3NleVtkZl9zZXkkc2NvcmUgJWluJSBiaW9tX2hlcmIsXSRzY29yZSwgc2VwPSAiLSIpCmRmX3NleVtkZl9zZXkkc2NvcmUgJWluJSBiaW9tX2Nhcm4sXSRzY29yZSA8LSBwYXN0ZSgiQyIsZGZfc2V5W2RmX3NleSRzY29yZSAlaW4lIGJpb21fY2FybixdJHNjb3JlLCBzZXA9ICItIikKYGBgCgoKYGBge3IgUHJpbnQgdGhlIHBvbGFyaGlzdG9ncmFtbTIsIGVjaG8gPSBULCBldmFsPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZT0gRiwgZmlnLmFsaWduPSJjZW50ZXIifQpzb3VyY2UocGFzdGUwKGRpcl9yZWZkYiwgInBvbGFySGlzdG9ncmFtLlIiKSkKcCA8LSBwb2xhckhpc3RvZ3JhbShkZl9zZXkgLCBmYW1pbHlMYWJlbD1ULCBpbm5lclJhZGl1cyA9IDAuMiwgc3BhY2VGYW1pbHkgPTcsIGNpcmNsZVByb3BvcnRpb24gPSAwLjg1KQpwICsgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBwb2xhcl9jb2wpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiLCBzaXplID0gMykpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ICJub25lIikgIyB0byBoaWRlIHRoZSBsZWdlbmQgYmVjYXVzZSBvZiB0aGUgc2l6ZQpgYGAK